Staging: Merge Ben Collins solo6x10 tree with upstream
authorGreg Kroah-Hartman <gregkh@suse.de>
Wed, 10 Nov 2010 00:12:37 +0000 (16:12 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 10 Nov 2010 00:12:37 +0000 (16:12 -0800)
There were some duplicate changes that needed to be hand-merged due to
fixes needed to keep .37 building and working properly.

Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
463 files changed:
arch/arm/mach-shmobile/Kconfig
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/clock-sh7372.c
arch/arm/mach-shmobile/include/mach/gpio.h
arch/arm/mach-shmobile/include/mach/sh7372.h
arch/m68k/include/asm/irqflags.h
arch/m68k/include/asm/machdep.h
arch/powerpc/kernel/kvm.c
arch/powerpc/kvm/booke_interrupts.S
arch/powerpc/kvm/e500.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/kvm/timing.c
arch/sh/Kconfig
arch/sh/Makefile
arch/sh/boards/Kconfig
arch/sh/boards/Makefile
arch/sh/boards/board-edosk7705.c [new file with mode: 0644]
arch/sh/boards/board-secureedge5410.c [new file with mode: 0644]
arch/sh/boards/mach-edosk7705/Makefile [deleted file]
arch/sh/boards/mach-edosk7705/io.c [deleted file]
arch/sh/boards/mach-edosk7705/setup.c [deleted file]
arch/sh/boards/mach-microdev/io.c
arch/sh/boards/mach-microdev/setup.c
arch/sh/boards/mach-se/7206/Makefile
arch/sh/boards/mach-se/7206/io.c [deleted file]
arch/sh/boards/mach-se/7206/irq.c
arch/sh/boards/mach-se/7206/setup.c
arch/sh/boards/mach-se/770x/Makefile
arch/sh/boards/mach-se/770x/io.c [deleted file]
arch/sh/boards/mach-se/770x/setup.c
arch/sh/boards/mach-se/7751/Makefile
arch/sh/boards/mach-se/7751/io.c [deleted file]
arch/sh/boards/mach-se/7751/setup.c
arch/sh/boards/mach-snapgear/Makefile [deleted file]
arch/sh/boards/mach-snapgear/io.c [deleted file]
arch/sh/boards/mach-snapgear/setup.c [deleted file]
arch/sh/boards/mach-systemh/Makefile [deleted file]
arch/sh/boards/mach-systemh/io.c [deleted file]
arch/sh/boards/mach-systemh/irq.c [deleted file]
arch/sh/boards/mach-systemh/setup.c [deleted file]
arch/sh/configs/secureedge5410_defconfig [new file with mode: 0644]
arch/sh/configs/snapgear_defconfig [deleted file]
arch/sh/configs/systemh_defconfig [deleted file]
arch/sh/include/asm/addrspace.h
arch/sh/include/asm/pgtable.h
arch/sh/include/asm/system.h
arch/sh/include/asm/system_32.h
arch/sh/include/asm/system_64.h
arch/sh/include/asm/uncached.h
arch/sh/include/mach-common/mach/edosk7705.h [deleted file]
arch/sh/include/mach-common/mach/microdev.h
arch/sh/include/mach-common/mach/secureedge5410.h [new file with mode: 0644]
arch/sh/include/mach-common/mach/snapgear.h [deleted file]
arch/sh/include/mach-common/mach/systemh7751.h [deleted file]
arch/sh/kernel/cpu/sh4a/clock-sh7724.c
arch/sh/mm/Kconfig
arch/sh/mm/consistent.c
arch/sh/mm/uncached.c
arch/sh/tools/mach-types
arch/tile/include/asm/highmem.h
arch/tile/include/asm/kmap_types.h
arch/tile/include/asm/pgtable.h
arch/tile/include/asm/stat.h
arch/tile/include/asm/unistd.h
arch/tile/kernel/compat.c
arch/tile/kernel/early_printk.c
arch/tile/kernel/hardwall.c
arch/tile/kernel/irq.c
arch/tile/kernel/machine_kexec.c
arch/tile/kernel/messaging.c
arch/tile/kernel/ptrace.c
arch/tile/kernel/reboot.c
arch/tile/kernel/setup.c
arch/tile/kernel/signal.c
arch/tile/kernel/smp.c
arch/tile/kernel/time.c
arch/tile/lib/memcpy_tile64.c
arch/tile/mm/highmem.c
arch/tile/mm/init.c
arch/tile/mm/pgtable.c
arch/x86/kvm/mmu.c
arch/x86/kvm/x86.c
drivers/Makefile
drivers/block/floppy.c
drivers/char/.gitignore [deleted file]
drivers/char/Makefile
drivers/char/consolemap.c [deleted file]
drivers/char/cp437.uni [deleted file]
drivers/char/defkeymap.c_shipped [deleted file]
drivers/char/defkeymap.map [deleted file]
drivers/char/keyboard.c [deleted file]
drivers/char/n_gsm.c [deleted file]
drivers/char/n_hdlc.c [deleted file]
drivers/char/n_r3964.c [deleted file]
drivers/char/n_tty.c [deleted file]
drivers/char/pty.c [deleted file]
drivers/char/selection.c [deleted file]
drivers/char/sysrq.c [deleted file]
drivers/char/tty_audit.c [deleted file]
drivers/char/tty_buffer.c [deleted file]
drivers/char/tty_io.c [deleted file]
drivers/char/tty_ioctl.c [deleted file]
drivers/char/tty_ldisc.c [deleted file]
drivers/char/tty_mutex.c [deleted file]
drivers/char/tty_port.c [deleted file]
drivers/char/vc_screen.c [deleted file]
drivers/char/vt.c [deleted file]
drivers/char/vt_ioctl.c [deleted file]
drivers/clocksource/sh_cmt.c
drivers/clocksource/sh_mtu2.c
drivers/clocksource/sh_tmu.c
drivers/firewire/ohci.c
drivers/hwmon/ltc4261.c
drivers/isdn/hisax/isar.c
drivers/leds/leds-net5501.c
drivers/net/atlx/atl1.c
drivers/net/bnx2x/bnx2x.h
drivers/net/bnx2x/bnx2x_hsi.h
drivers/net/bnx2x/bnx2x_link.c
drivers/net/caif/caif_spi.c
drivers/net/caif/caif_spi_slave.c
drivers/net/cxgb3/cxgb3_main.c
drivers/net/cxgb4/cxgb4_main.c
drivers/net/cxgb4vf/cxgb4vf_main.c
drivers/net/ibm_newemac/core.c
drivers/net/jme.c
drivers/net/netxen/netxen_nic_main.c
drivers/net/qlcnic/qlcnic_main.c
drivers/net/smsc911x.h
drivers/net/tulip/de2104x.c
drivers/net/usb/usbnet.c
drivers/net/wireless/ipw2x00/libipw_module.c
drivers/rtc/rtc-ds1302.c
drivers/sh/clk/core.c
drivers/sh/intc/core.c
drivers/sh/intc/dynamic.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif_scatter.c
drivers/staging/ath6kl/os/linux/include/athendpack_linux.h [deleted file]
drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h [deleted file]
drivers/staging/batman-adv/main.c
drivers/staging/batman-adv/main.h
drivers/staging/batman-adv/routing.c
drivers/staging/batman-adv/soft-interface.c
drivers/staging/batman-adv/vis.c
drivers/staging/bcm/Adapter.h
drivers/staging/bcm/Arp.c [deleted file]
drivers/staging/bcm/Bcmchar.c
drivers/staging/bcm/Bcmnet.c
drivers/staging/bcm/CmHost.c
drivers/staging/bcm/CmHost.h
drivers/staging/bcm/DDRInit.c
drivers/staging/bcm/Debug.c [deleted file]
drivers/staging/bcm/Debug.h
drivers/staging/bcm/HandleControlPacket.c
drivers/staging/bcm/HostMibs.h [deleted file]
drivers/staging/bcm/IPv6Protocol.c
drivers/staging/bcm/IPv6ProtocolHdr.h
drivers/staging/bcm/InterfaceDld.c
drivers/staging/bcm/InterfaceIdleMode.c
drivers/staging/bcm/InterfaceIdleMode.h
drivers/staging/bcm/InterfaceInit.c
drivers/staging/bcm/InterfaceInit.h
drivers/staging/bcm/InterfaceIsr.c
drivers/staging/bcm/InterfaceMisc.c
drivers/staging/bcm/InterfaceMisc.h
drivers/staging/bcm/InterfaceRx.c
drivers/staging/bcm/InterfaceTx.c
drivers/staging/bcm/InterfaceTx.h
drivers/staging/bcm/Interfacemain.h [deleted file]
drivers/staging/bcm/LeakyBucket.c
drivers/staging/bcm/Macros.h
drivers/staging/bcm/Makefile
drivers/staging/bcm/Misc.c
drivers/staging/bcm/Osal_Misc.c [deleted file]
drivers/staging/bcm/PHSModule.c
drivers/staging/bcm/PHSModule.h
drivers/staging/bcm/Protocol.h
drivers/staging/bcm/Prototypes.h
drivers/staging/bcm/Qos.c
drivers/staging/bcm/TODO
drivers/staging/bcm/Transmit.c
drivers/staging/bcm/cntrl_SignalingInterface.h
drivers/staging/bcm/headers.h
drivers/staging/bcm/hostmibs.c
drivers/staging/bcm/led_control.c
drivers/staging/bcm/nvm.c
drivers/staging/bcm/nvm.h
drivers/staging/bcm/osal_misc.h [deleted file]
drivers/staging/brcm80211/brcmfmac/bcmsdh.c
drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c
drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c
drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c
drivers/staging/brcm80211/brcmfmac/dhd_cdc.c
drivers/staging/brcm80211/brcmfmac/dhd_common.c
drivers/staging/brcm80211/brcmfmac/dhd_custom_gpio.c
drivers/staging/brcm80211/brcmfmac/dhd_linux.c
drivers/staging/brcm80211/brcmfmac/dhd_linux_sched.c
drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c
drivers/staging/brcm80211/brcmfmac/wl_iw.c
drivers/staging/brcm80211/include/bcmdefs.h
drivers/staging/brcm80211/include/bcmutils.h
drivers/staging/brcm80211/include/d11.h
drivers/staging/brcm80211/include/epivers.h [deleted file]
drivers/staging/brcm80211/include/linux_osl.h
drivers/staging/brcm80211/include/linuxver.h [deleted file]
drivers/staging/brcm80211/include/osl.h
drivers/staging/brcm80211/include/wlioctl.h
drivers/staging/brcm80211/phy/wlc_phy_cmn.c
drivers/staging/brcm80211/phy/wlc_phy_lcn.c
drivers/staging/brcm80211/phy/wlc_phy_n.c
drivers/staging/brcm80211/phy/wlc_phytbl_lcn.c
drivers/staging/brcm80211/phy/wlc_phytbl_n.c
drivers/staging/brcm80211/sys/wl_mac80211.c
drivers/staging/brcm80211/sys/wlc_alloc.c
drivers/staging/brcm80211/sys/wlc_ampdu.c
drivers/staging/brcm80211/sys/wlc_antsel.c
drivers/staging/brcm80211/sys/wlc_bmac.c
drivers/staging/brcm80211/sys/wlc_channel.c
drivers/staging/brcm80211/sys/wlc_event.c
drivers/staging/brcm80211/sys/wlc_mac80211.c
drivers/staging/brcm80211/sys/wlc_mac80211.h
drivers/staging/brcm80211/sys/wlc_phy_shim.c
drivers/staging/brcm80211/sys/wlc_pub.h
drivers/staging/brcm80211/sys/wlc_rate.c
drivers/staging/brcm80211/sys/wlc_stf.c
drivers/staging/brcm80211/util/aiutils.c
drivers/staging/brcm80211/util/bcmotp.c
drivers/staging/brcm80211/util/bcmsrom.c
drivers/staging/brcm80211/util/bcmutils.c
drivers/staging/brcm80211/util/bcmwifi.c
drivers/staging/brcm80211/util/hnddma.c
drivers/staging/brcm80211/util/hndpmu.c
drivers/staging/brcm80211/util/linux_osl.c
drivers/staging/brcm80211/util/nicpci.c
drivers/staging/brcm80211/util/sbutils.c
drivers/staging/brcm80211/util/siutils.c
drivers/staging/comedi/drivers/addi-data/addi_common.c
drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c
drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c
drivers/staging/comedi/drivers/rtd520.c
drivers/staging/cptm1217/Kconfig [new file with mode: 0644]
drivers/staging/cptm1217/Makefile [new file with mode: 0644]
drivers/staging/cptm1217/TODO [new file with mode: 0644]
drivers/staging/cptm1217/clearpad_tm1217.c [new file with mode: 0644]
drivers/staging/cptm1217/cp_tm1217.h [new file with mode: 0644]
drivers/staging/frontier/alphatrack.c
drivers/staging/ft1000/ft1000-usb/ft1000_chdev.c
drivers/staging/ft1000/ft1000-usb/ft1000_download.c
drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
drivers/staging/ft1000/ft1000-usb/ft1000_hw.h
drivers/staging/ft1000/ft1000-usb/ft1000_proc.c
drivers/staging/ft1000/ft1000-usb/ft1000_usb.c
drivers/staging/ft1000/ft1000-usb/ft1000_usb.h
drivers/staging/iio/Kconfig
drivers/staging/iio/Makefile
drivers/staging/iio/TODO
drivers/staging/iio/accel/Kconfig
drivers/staging/iio/accel/Makefile
drivers/staging/iio/accel/accel.h
drivers/staging/iio/accel/adis16201.h [new file with mode: 0644]
drivers/staging/iio/accel/adis16201_core.c [new file with mode: 0644]
drivers/staging/iio/accel/adis16201_ring.c [new file with mode: 0644]
drivers/staging/iio/accel/adis16201_trigger.c [new file with mode: 0644]
drivers/staging/iio/accel/adis16203.h [new file with mode: 0644]
drivers/staging/iio/accel/adis16203_core.c [new file with mode: 0644]
drivers/staging/iio/accel/adis16203_ring.c [new file with mode: 0644]
drivers/staging/iio/accel/adis16203_trigger.c [new file with mode: 0644]
drivers/staging/iio/accel/adis16204.h [new file with mode: 0644]
drivers/staging/iio/accel/adis16204_core.c [new file with mode: 0644]
drivers/staging/iio/accel/adis16204_ring.c [new file with mode: 0644]
drivers/staging/iio/accel/adis16204_trigger.c [new file with mode: 0644]
drivers/staging/iio/accel/adis16209_ring.c
drivers/staging/iio/adc/Kconfig
drivers/staging/iio/adc/Makefile
drivers/staging/iio/adc/ad7150.c [new file with mode: 0644]
drivers/staging/iio/adc/ad7152.c [new file with mode: 0644]
drivers/staging/iio/adc/ad7291.c [new file with mode: 0644]
drivers/staging/iio/adc/ad7298.c [new file with mode: 0644]
drivers/staging/iio/adc/ad7314.c [new file with mode: 0644]
drivers/staging/iio/adc/ad7745.c [new file with mode: 0644]
drivers/staging/iio/adc/ad7816.c [new file with mode: 0644]
drivers/staging/iio/adc/adt7310.c [new file with mode: 0644]
drivers/staging/iio/adc/adt7410.c [new file with mode: 0644]
drivers/staging/iio/adc/adt75.c [new file with mode: 0644]
drivers/staging/iio/addac/Kconfig [new file with mode: 0644]
drivers/staging/iio/addac/Makefile [new file with mode: 0644]
drivers/staging/iio/addac/adt7316-i2c.c [new file with mode: 0644]
drivers/staging/iio/addac/adt7316-spi.c [new file with mode: 0644]
drivers/staging/iio/addac/adt7316.c [new file with mode: 0644]
drivers/staging/iio/addac/adt7316.h [new file with mode: 0644]
drivers/staging/iio/dac/Kconfig [new file with mode: 0644]
drivers/staging/iio/dac/Makefile [new file with mode: 0644]
drivers/staging/iio/dac/ad5624r.h [new file with mode: 0644]
drivers/staging/iio/dac/ad5624r_spi.c [new file with mode: 0644]
drivers/staging/iio/dac/dac.h [new file with mode: 0644]
drivers/staging/iio/dds/Kconfig [new file with mode: 0644]
drivers/staging/iio/dds/Makefile [new file with mode: 0644]
drivers/staging/iio/dds/ad5930.c [new file with mode: 0644]
drivers/staging/iio/dds/ad9832.c [new file with mode: 0644]
drivers/staging/iio/dds/ad9850.c [new file with mode: 0644]
drivers/staging/iio/dds/ad9852.c [new file with mode: 0644]
drivers/staging/iio/dds/ad9910.c [new file with mode: 0644]
drivers/staging/iio/dds/ad9951.c [new file with mode: 0644]
drivers/staging/iio/gyro/Kconfig
drivers/staging/iio/gyro/Makefile
drivers/staging/iio/gyro/adis16060.h [new file with mode: 0644]
drivers/staging/iio/gyro/adis16060_core.c [new file with mode: 0644]
drivers/staging/iio/gyro/adis16080.h [new file with mode: 0644]
drivers/staging/iio/gyro/adis16080_core.c [new file with mode: 0644]
drivers/staging/iio/gyro/adis16130.h [new file with mode: 0644]
drivers/staging/iio/gyro/adis16130_core.c [new file with mode: 0644]
drivers/staging/iio/gyro/adis16251.h [new file with mode: 0644]
drivers/staging/iio/gyro/adis16251_core.c [new file with mode: 0644]
drivers/staging/iio/gyro/adis16260_core.c
drivers/staging/iio/imu/adis16350_core.c
drivers/staging/iio/meter/Kconfig [new file with mode: 0644]
drivers/staging/iio/meter/Makefile [new file with mode: 0644]
drivers/staging/iio/meter/ade7753.c [new file with mode: 0644]
drivers/staging/iio/meter/ade7753.h [new file with mode: 0644]
drivers/staging/iio/meter/ade7754.c [new file with mode: 0644]
drivers/staging/iio/meter/ade7754.h [new file with mode: 0644]
drivers/staging/iio/meter/ade7758.h [new file with mode: 0644]
drivers/staging/iio/meter/ade7758_core.c [new file with mode: 0644]
drivers/staging/iio/meter/ade7758_ring.c [new file with mode: 0644]
drivers/staging/iio/meter/ade7758_trigger.c [new file with mode: 0644]
drivers/staging/iio/meter/ade7759.c [new file with mode: 0644]
drivers/staging/iio/meter/ade7759.h [new file with mode: 0644]
drivers/staging/iio/meter/ade7854-i2c.c [new file with mode: 0644]
drivers/staging/iio/meter/ade7854-spi.c [new file with mode: 0644]
drivers/staging/iio/meter/ade7854.c [new file with mode: 0644]
drivers/staging/iio/meter/ade7854.h [new file with mode: 0644]
drivers/staging/iio/meter/meter.h [new file with mode: 0644]
drivers/staging/iio/resolver/Kconfig [new file with mode: 0644]
drivers/staging/iio/resolver/Makefile [new file with mode: 0644]
drivers/staging/iio/resolver/ad2s120x.c [new file with mode: 0644]
drivers/staging/iio/resolver/ad2s1210.c [new file with mode: 0644]
drivers/staging/iio/resolver/ad2s90.c [new file with mode: 0644]
drivers/staging/iio/sysfs.h
drivers/staging/intel_sst/intel_sst.c
drivers/staging/intel_sst/intel_sst_app_interface.c
drivers/staging/intel_sst/intel_sst_drv_interface.c
drivers/staging/intel_sst/intel_sst_dsp.c
drivers/staging/intel_sst/intel_sst_ipc.c
drivers/staging/intel_sst/intel_sst_pvt.c
drivers/staging/intel_sst/intel_sst_stream.c
drivers/staging/intel_sst/intel_sst_stream_encoded.c
drivers/staging/intel_sst/intelmid.c
drivers/staging/intel_sst/intelmid_ctrl.c
drivers/staging/intel_sst/intelmid_msic_control.c
drivers/staging/intel_sst/intelmid_pvt.c
drivers/staging/intel_sst/intelmid_v0_control.c
drivers/staging/intel_sst/intelmid_v1_control.c
drivers/staging/intel_sst/intelmid_v2_control.c
drivers/staging/msm/Makefile
drivers/staging/pohmelfs/crypto.c
drivers/staging/rtl8192u/r8192U_core.c
drivers/staging/ste_rmi4/Kconfig [new file with mode: 0644]
drivers/staging/ste_rmi4/Makefile [new file with mode: 0644]
drivers/staging/ste_rmi4/TODO [new file with mode: 0644]
drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c [new file with mode: 0644]
drivers/staging/ste_rmi4/synaptics_i2c_rmi4.h [new file with mode: 0644]
drivers/staging/vt6656/card.c
drivers/staging/vt6656/dpc.c
drivers/staging/vt6656/rxtx.c
drivers/staging/vt6656/tkip.c
drivers/staging/winbond/core.h
drivers/staging/winbond/mds.c
drivers/staging/winbond/mds_f.h
drivers/staging/winbond/mto.c
drivers/staging/winbond/phy_calibration.c
drivers/staging/winbond/phy_calibration.h
drivers/staging/winbond/reg.c
drivers/staging/winbond/wb35reg_f.h
drivers/staging/winbond/wb35reg_s.h
drivers/staging/winbond/wb35rx.c
drivers/staging/winbond/wb35rx_f.h
drivers/staging/winbond/wb35tx.c
drivers/staging/winbond/wb35tx_f.h
drivers/staging/winbond/wbhal.h [new file with mode: 0644]
drivers/staging/winbond/wbhal_f.h [deleted file]
drivers/staging/winbond/wbhal_s.h [deleted file]
drivers/staging/winbond/wbusb.c
drivers/staging/wlags49_h2/wl_sysfs.c
drivers/staging/xgifb/XGI_main_26.c
drivers/tty/Makefile [new file with mode: 0644]
drivers/tty/n_gsm.c [new file with mode: 0644]
drivers/tty/n_hdlc.c [new file with mode: 0644]
drivers/tty/n_r3964.c [new file with mode: 0644]
drivers/tty/n_tty.c [new file with mode: 0644]
drivers/tty/pty.c [new file with mode: 0644]
drivers/tty/sysrq.c [new file with mode: 0644]
drivers/tty/tty_audit.c [new file with mode: 0644]
drivers/tty/tty_buffer.c [new file with mode: 0644]
drivers/tty/tty_io.c [new file with mode: 0644]
drivers/tty/tty_ioctl.c [new file with mode: 0644]
drivers/tty/tty_ldisc.c [new file with mode: 0644]
drivers/tty/tty_mutex.c [new file with mode: 0644]
drivers/tty/tty_port.c [new file with mode: 0644]
drivers/tty/vt/.gitignore [new file with mode: 0644]
drivers/tty/vt/Makefile [new file with mode: 0644]
drivers/tty/vt/consolemap.c [new file with mode: 0644]
drivers/tty/vt/cp437.uni [new file with mode: 0644]
drivers/tty/vt/defkeymap.c_shipped [new file with mode: 0644]
drivers/tty/vt/defkeymap.map [new file with mode: 0644]
drivers/tty/vt/keyboard.c [new file with mode: 0644]
drivers/tty/vt/selection.c [new file with mode: 0644]
drivers/tty/vt/vc_screen.c [new file with mode: 0644]
drivers/tty/vt/vt.c [new file with mode: 0644]
drivers/tty/vt/vt_ioctl.c [new file with mode: 0644]
drivers/usb/gadget/u_ether.c
fs/cifs/TODO
fs/cifs/cifs_fs_sb.h
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/ioctl.c
fs/cifs/misc.c
fs/ext4/ext4.h
fs/ext4/inode.c
fs/ext4/mballoc.c
fs/ext4/page-io.c
fs/ext4/super.c
include/asm-generic/stat.h
include/linux/mmc/sh_mmcif.h
include/linux/sh_clk.h
include/linux/sh_timer.h
include/net/caif/caif_dev.h
include/net/caif/caif_spi.h
include/net/caif/cfcnfg.h
include/net/netlink.h
include/trace/events/ext4.h
kernel/exit.c
kernel/relay.c
kernel/watchdog.c
net/caif/caif_config_util.c
net/caif/caif_dev.c
net/caif/caif_socket.c
net/caif/cfcnfg.c
net/caif/cfctrl.c
net/caif/cfdbgl.c
net/caif/cfrfml.c
net/core/dev.c
net/ipv4/fib_lookup.h
net/ipv4/inet_diag.c
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/netfilter/nf_nat_core.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/route.c
net/l2tp/l2tp_debugfs.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_proto.c
net/rds/loop.c
net/rds/tcp.c
net/sched/cls_cgroup.c
net/sched/em_text.c
net/x25/x25_facilities.c
net/x25/x25_in.c

index 54b479c35ee01d2db0f2f5c75f9786f329293146..51dcd59eda6a1aeb965d02b5b94bf66e8737e2ff 100644 (file)
@@ -116,4 +116,6 @@ endmenu
 config SH_CLK_CPG
        bool
 
+source "drivers/sh/Kconfig"
+
 endif
index 46ca4d4abf910aad98652306a7d41bfa7ccdcfe8..32d9e2816e569a98a9a6525e9aab6c757053388f 100644 (file)
@@ -565,12 +565,50 @@ static struct platform_device *qhd_devices[] __initdata = {
 
 /* FSI */
 #define IRQ_FSI                evt2irq(0x1840)
+
+static int fsi_set_rate(int is_porta, int rate)
+{
+       struct clk *fsib_clk;
+       struct clk *fdiv_clk = &sh7372_fsidivb_clk;
+       int ret;
+
+       /* set_rate is not needed if port A */
+       if (is_porta)
+               return 0;
+
+       fsib_clk = clk_get(NULL, "fsib_clk");
+       if (IS_ERR(fsib_clk))
+               return -EINVAL;
+
+       switch (rate) {
+       case 48000:
+               clk_set_rate(fsib_clk, clk_round_rate(fsib_clk, 85428000));
+               clk_set_rate(fdiv_clk, clk_round_rate(fdiv_clk, 12204000));
+               ret = SH_FSI_ACKMD_256 | SH_FSI_BPFMD_64;
+               break;
+       default:
+               pr_err("unsupported rate in FSI2 port B\n");
+               ret = -EINVAL;
+               break;
+       }
+
+       clk_put(fsib_clk);
+
+       return ret;
+}
+
 static struct sh_fsi_platform_info fsi_info = {
        .porta_flags = SH_FSI_BRS_INV |
                       SH_FSI_OUT_SLAVE_MODE |
                       SH_FSI_IN_SLAVE_MODE |
                       SH_FSI_OFMT(PCM) |
                       SH_FSI_IFMT(PCM),
+
+       .portb_flags = SH_FSI_BRS_INV |
+                      SH_FSI_BRM_INV |
+                      SH_FSI_LRS_INV |
+                      SH_FSI_OFMT(SPDIF),
+       .set_rate = fsi_set_rate,
 };
 
 static struct resource fsi_resources[] = {
@@ -634,6 +672,7 @@ static struct platform_device lcdc1_device = {
 static struct sh_mobile_hdmi_info hdmi_info = {
        .lcd_chan = &sh_mobile_lcdc1_info.ch[0],
        .lcd_dev = &lcdc1_device.dev,
+       .flags = HDMI_SND_SRC_SPDIF,
 };
 
 static struct resource hdmi_resources[] = {
@@ -992,6 +1031,7 @@ static void __init ap4evb_map_io(void)
 
 #define GPIO_PORT9CR   0xE6051009
 #define GPIO_PORT10CR  0xE605100A
+#define USCCR1         0xE6058144
 static void __init ap4evb_init(void)
 {
        u32 srcr4;
@@ -1062,7 +1102,7 @@ static void __init ap4evb_init(void)
        /* setup USB phy */
        __raw_writew(0x8a0a, 0xE6058130);       /* USBCR2 */
 
-       /* enable FSI2 */
+       /* enable FSI2 port A (ak4643) */
        gpio_request(GPIO_FN_FSIAIBT,   NULL);
        gpio_request(GPIO_FN_FSIAILR,   NULL);
        gpio_request(GPIO_FN_FSIAISLD,  NULL);
@@ -1079,6 +1119,10 @@ static void __init ap4evb_init(void)
        gpio_request(GPIO_PORT41, NULL);
        gpio_direction_input(GPIO_PORT41);
 
+       /* setup FSI2 port B (HDMI) */
+       gpio_request(GPIO_FN_FSIBCK, NULL);
+       __raw_writew(__raw_readw(USCCR1) & ~(1 << 6), USCCR1); /* use SPDIF */
+
        /* set SPU2 clock to 119.6 MHz */
        clk = clk_get(NULL, "spu_clk");
        if (!IS_ERR(clk)) {
index 8565aefa21fd3c2e62877c3de33a43d8390dda76..7db31e6c6bf2085908cb66ce669238488c5aa444 100644 (file)
@@ -50,6 +50,9 @@
 #define SMSTPCR3       0xe615013c
 #define SMSTPCR4       0xe6150140
 
+#define FSIDIVA                0xFE1F8000
+#define FSIDIVB                0xFE1F8008
+
 /* Platforms must set frequency on their DV_CLKI pin */
 struct clk sh7372_dv_clki_clk = {
 };
@@ -288,6 +291,7 @@ struct clk sh7372_pllc2_clk = {
        .ops            = &pllc2_clk_ops,
        .parent         = &extal1_div2_clk,
        .freq_table     = pllc2_freq_table,
+       .nr_freqs       = ARRAY_SIZE(pllc2_freq_table) - 1,
        .parent_table   = pllc2_parent,
        .parent_num     = ARRAY_SIZE(pllc2_parent),
 };
@@ -417,6 +421,101 @@ static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = {
                                      fsibckcr_parent, ARRAY_SIZE(fsibckcr_parent), 6, 2),
 };
 
+/* FSI DIV */
+static unsigned long fsidiv_recalc(struct clk *clk)
+{
+       unsigned long value;
+
+       value = __raw_readl(clk->mapping->base);
+
+       if ((value & 0x3) != 0x3)
+               return 0;
+
+       value >>= 16;
+       if (value < 2)
+               return 0;
+
+       return clk->parent->rate / value;
+}
+
+static long fsidiv_round_rate(struct clk *clk, unsigned long rate)
+{
+       return clk_rate_div_range_round(clk, 2, 0xffff, rate);
+}
+
+static void fsidiv_disable(struct clk *clk)
+{
+       __raw_writel(0, clk->mapping->base);
+}
+
+static int fsidiv_enable(struct clk *clk)
+{
+       unsigned long value;
+
+       value  = __raw_readl(clk->mapping->base) >> 16;
+       if (value < 2) {
+               fsidiv_disable(clk);
+               return -ENOENT;
+       }
+
+       __raw_writel((value << 16) | 0x3, clk->mapping->base);
+
+       return 0;
+}
+
+static int fsidiv_set_rate(struct clk *clk,
+                          unsigned long rate, int algo_id)
+{
+       int idx;
+
+       if (clk->parent->rate == rate) {
+               fsidiv_disable(clk);
+               return 0;
+       }
+
+       idx = (clk->parent->rate / rate) & 0xffff;
+       if (idx < 2)
+               return -ENOENT;
+
+       __raw_writel(idx << 16, clk->mapping->base);
+       return fsidiv_enable(clk);
+}
+
+static struct clk_ops fsidiv_clk_ops = {
+       .recalc         = fsidiv_recalc,
+       .round_rate     = fsidiv_round_rate,
+       .set_rate       = fsidiv_set_rate,
+       .enable         = fsidiv_enable,
+       .disable        = fsidiv_disable,
+};
+
+static struct clk_mapping sh7372_fsidiva_clk_mapping = {
+       .phys   = FSIDIVA,
+       .len    = 8,
+};
+
+struct clk sh7372_fsidiva_clk = {
+       .ops            = &fsidiv_clk_ops,
+       .parent         = &div6_reparent_clks[DIV6_FSIA], /* late install */
+       .mapping        = &sh7372_fsidiva_clk_mapping,
+};
+
+static struct clk_mapping sh7372_fsidivb_clk_mapping = {
+       .phys   = FSIDIVB,
+       .len    = 8,
+};
+
+struct clk sh7372_fsidivb_clk = {
+       .ops            = &fsidiv_clk_ops,
+       .parent         = &div6_reparent_clks[DIV6_FSIB],  /* late install */
+       .mapping        = &sh7372_fsidivb_clk_mapping,
+};
+
+static struct clk *late_main_clks[] = {
+       &sh7372_fsidiva_clk,
+       &sh7372_fsidivb_clk,
+};
+
 enum { MSTP001,
        MSTP131, MSTP130,
        MSTP129, MSTP128, MSTP127, MSTP126, MSTP125,
@@ -585,6 +684,9 @@ void __init sh7372_clock_init(void)
        if (!ret)
                ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
 
+       for (k = 0; !ret && (k < ARRAY_SIZE(late_main_clks)); k++)
+               ret = clk_register(late_main_clks[k]);
+
        clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 
        if (!ret)
index 5bc6bd444d7236016eac8c004f764da16a481380..2b1bb9e43ddadc8b83505b021c5ca7ae4f4704c5 100644 (file)
@@ -35,12 +35,12 @@ static inline int gpio_cansleep(unsigned gpio)
 
 static inline int gpio_to_irq(unsigned gpio)
 {
-       return -ENOSYS;
+       return __gpio_to_irq(gpio);
 }
 
 static inline int irq_to_gpio(unsigned int irq)
 {
-       return -EINVAL;
+       return -ENOSYS;
 }
 
 #endif /* CONFIG_GPIOLIB */
index 147775a94bcefa528d662f8d49d0d93b6302cddf..e4f9004e710382574fcf5e23cb67339fa0f53148 100644 (file)
@@ -464,5 +464,7 @@ extern struct clk sh7372_dv_clki_div2_clk;
 extern struct clk sh7372_pllc2_clk;
 extern struct clk sh7372_fsiack_clk;
 extern struct clk sh7372_fsibck_clk;
+extern struct clk sh7372_fsidiva_clk;
+extern struct clk sh7372_fsidivb_clk;
 
 #endif /* __ASM_SH7372_H__ */
index 4a5b284a15500f4a1a8525dab1609d34310599c0..7ef4115b8c4a59f0248df2273184ab5e2ed8f053 100644 (file)
@@ -2,7 +2,9 @@
 #define _M68K_IRQFLAGS_H
 
 #include <linux/types.h>
+#ifdef CONFIG_MMU
 #include <linux/hardirq.h>
+#endif
 #include <linux/preempt.h>
 #include <asm/thread_info.h>
 #include <asm/entry.h>
index 789f3b2de0e9bf2f63720bcc0c522c686e9c9d31..415d5484916c4d9e6ec1981e380cfe9a0f1ab4de 100644 (file)
@@ -40,5 +40,6 @@ extern unsigned long hw_timer_offset(void);
 extern irqreturn_t arch_timer_interrupt(int irq, void *dummy);
 
 extern void config_BSP(char *command, int len);
+extern void do_IRQ(int irq, struct pt_regs *fp);
 
 #endif /* _M68K_MACHDEP_H */
index 428d0e538aec50880f23b8b097698572a2d2a01a..b06bdae04064f59d2c4c4c98e76304dee6ca98c8 100644 (file)
@@ -127,7 +127,7 @@ static void kvm_patch_ins_nop(u32 *inst)
 
 static void kvm_patch_ins_b(u32 *inst, int addr)
 {
-#ifdef CONFIG_RELOCATABLE
+#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_PPC_BOOK3S)
        /* On relocatable kernels interrupts handlers and our code
           can be in different regions, so we don't patch them */
 
index 049846911ce4d18d8097507b9be0caa8d767733c..1cc471faac2dd4bac032a956860b4f10d29170cb 100644 (file)
@@ -416,7 +416,7 @@ lightweight_exit:
        lwz     r3, VCPU_PC(r4)
        mtsrr0  r3
        lwz     r3, VCPU_SHARED(r4)
-       lwz     r3, VCPU_SHARED_MSR(r3)
+       lwz     r3, (VCPU_SHARED_MSR + 4)(r3)
        oris    r3, r3, KVMPPC_MSR_MASK@h
        ori     r3, r3, KVMPPC_MSR_MASK@l
        mtsrr1  r3
index 71750f2dd5d34378c963acf7bf9d3a69a15863cc..e3768ee9b59537bf92eceb853fa9edf56d7d5b6c 100644 (file)
@@ -138,8 +138,8 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
        struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
 
        free_page((unsigned long)vcpu->arch.shared);
-       kvmppc_e500_tlb_uninit(vcpu_e500);
        kvm_vcpu_uninit(vcpu);
+       kvmppc_e500_tlb_uninit(vcpu_e500);
        kmem_cache_free(kvm_vcpu_cache, vcpu_e500);
 }
 
index 2f87a1627f6cff35604f96e8e041cffd9af071ff..38f756f2505389ac5f59eb9ae3921ef72175eea1 100644 (file)
@@ -617,6 +617,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
        switch (ioctl) {
        case KVM_PPC_GET_PVINFO: {
                struct kvm_ppc_pvinfo pvinfo;
+               memset(&pvinfo, 0, sizeof(pvinfo));
                r = kvm_vm_ioctl_get_pvinfo(&pvinfo);
                if (copy_to_user(argp, &pvinfo, sizeof(pvinfo))) {
                        r = -EFAULT;
index 46fa04f12a9b979c7cbe50c703d43e2c2705604e..a021f5827a336ce97b6c62ed5b8d0ca625d571bf 100644 (file)
@@ -35,7 +35,6 @@ void kvmppc_init_timing_stats(struct kvm_vcpu *vcpu)
        int i;
 
        /* pause guest execution to avoid concurrent updates */
-       local_irq_disable();
        mutex_lock(&vcpu->mutex);
 
        vcpu->arch.last_exit_type = 0xDEAD;
@@ -51,7 +50,6 @@ void kvmppc_init_timing_stats(struct kvm_vcpu *vcpu)
        vcpu->arch.timing_last_enter.tv64 = 0;
 
        mutex_unlock(&vcpu->mutex);
-       local_irq_enable();
 }
 
 static void add_exit_timing(struct kvm_vcpu *vcpu, u64 duration, int type)
index 5c075f562ebae912476974f20faee1bfaeec707d..7f217b3a50a806b7347f991b588397011aa3388e 100644 (file)
@@ -193,6 +193,7 @@ config CPU_SH2
 config CPU_SH2A
        bool
        select CPU_SH2
+       select UNCACHED_MAPPING
 
 config CPU_SH3
        bool
index 307b3a4a790b98b61bd3cb893dfa155ff4983e0b..9c8c6e1a2a154d4dff50db8d0d532201c5f991be 100644 (file)
@@ -133,10 +133,7 @@ machdir-$(CONFIG_SOLUTION_ENGINE)          += mach-se
 machdir-$(CONFIG_SH_HP6XX)                     += mach-hp6xx
 machdir-$(CONFIG_SH_DREAMCAST)                 += mach-dreamcast
 machdir-$(CONFIG_SH_SH03)                      += mach-sh03
-machdir-$(CONFIG_SH_SECUREEDGE5410)            += mach-snapgear
 machdir-$(CONFIG_SH_RTS7751R2D)                        += mach-r2d
-machdir-$(CONFIG_SH_7751_SYSTEMH)              += mach-systemh
-machdir-$(CONFIG_SH_EDOSK7705)                 += mach-edosk7705
 machdir-$(CONFIG_SH_HIGHLANDER)                        += mach-highlander
 machdir-$(CONFIG_SH_MIGOR)                     += mach-migor
 machdir-$(CONFIG_SH_AP325RXA)                  += mach-ap325rxa
index 9c94711aa6caee785b152ba7be282b98a6b6d285..2018c7ea4c93f49d53d7f1ff82f32db2b85e85bc 100644 (file)
@@ -81,13 +81,6 @@ config SH_7343_SOLUTION_ENGINE
          Select 7343 SolutionEngine if configuring for a Hitachi
          SH7343 (SH-Mobile 3AS) evaluation board.
 
-config SH_7751_SYSTEMH
-       bool "SystemH7751R"
-       depends on CPU_SUBTYPE_SH7751R
-       help
-         Select SystemH if you are configuring for a Renesas SystemH
-         7751R evaluation board.
-
 config SH_HP6XX
        bool "HP6XX"
        select SYS_SUPPORTS_APM_EMULATION
index 38ef655cc0f08cfe0f881b053f421e9861412556..be7d11d04b26a3abcaeacde829e496f970903c33 100644 (file)
@@ -2,10 +2,12 @@
 # Specific board support, not covered by a mach group.
 #
 obj-$(CONFIG_SH_MAGIC_PANEL_R2)        += board-magicpanelr2.o
+obj-$(CONFIG_SH_SECUREEDGE5410)        += board-secureedge5410.o
 obj-$(CONFIG_SH_SH2007)                += board-sh2007.o
 obj-$(CONFIG_SH_SH7785LCR)     += board-sh7785lcr.o
 obj-$(CONFIG_SH_URQUELL)       += board-urquell.o
 obj-$(CONFIG_SH_SHMIN)         += board-shmin.o
+obj-$(CONFIG_SH_EDOSK7705)     += board-edosk7705.o
 obj-$(CONFIG_SH_EDOSK7760)     += board-edosk7760.o
 obj-$(CONFIG_SH_ESPT)          += board-espt.o
 obj-$(CONFIG_SH_POLARIS)       += board-polaris.o
diff --git a/arch/sh/boards/board-edosk7705.c b/arch/sh/boards/board-edosk7705.c
new file mode 100644 (file)
index 0000000..4cb3bb7
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * arch/sh/boards/renesas/edosk7705/setup.c
+ *
+ * Copyright (C) 2000  Kazumoto Kojima
+ *
+ * Hitachi SolutionEngine Support.
+ *
+ * Modified for edosk7705 development
+ * board by S. Dunn, 2003.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/smc91x.h>
+#include <asm/machvec.h>
+#include <asm/sizes.h>
+
+#define SMC_IOBASE     0xA2000000
+#define SMC_IO_OFFSET  0x300
+#define SMC_IOADDR     (SMC_IOBASE + SMC_IO_OFFSET)
+
+#define ETHERNET_IRQ   0x09
+
+static void __init sh_edosk7705_init_irq(void)
+{
+       make_imask_irq(ETHERNET_IRQ);
+}
+
+/* eth initialization functions */
+static struct smc91x_platdata smc91x_info = {
+       .flags = SMC91X_USE_16BIT | SMC91X_IO_SHIFT_1 | IORESOURCE_IRQ_LOWLEVEL,
+};
+
+static struct resource smc91x_res[] = {
+       [0] = {
+               .start  = SMC_IOADDR,
+               .end    = SMC_IOADDR + SZ_32 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = ETHERNET_IRQ,
+               .end    = ETHERNET_IRQ,
+               .flags  = IORESOURCE_IRQ ,
+       }
+};
+
+static struct platform_device smc91x_dev = {
+       .name           = "smc91x",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(smc91x_res),
+       .resource       = smc91x_res,
+
+       .dev    = {
+               .platform_data  = &smc91x_info,
+       },
+};
+
+/* platform init code */
+static struct platform_device *edosk7705_devices[] __initdata = {
+       &smc91x_dev,
+};
+
+static int __init init_edosk7705_devices(void)
+{
+       return platform_add_devices(edosk7705_devices,
+                                   ARRAY_SIZE(edosk7705_devices));
+}
+__initcall(init_edosk7705_devices);
+
+/*
+ * The Machine Vector
+ */
+static struct sh_machine_vector mv_edosk7705 __initmv = {
+       .mv_name                = "EDOSK7705",
+       .mv_nr_irqs             = 80,
+       .mv_init_irq            = sh_edosk7705_init_irq,
+};
diff --git a/arch/sh/boards/board-secureedge5410.c b/arch/sh/boards/board-secureedge5410.c
new file mode 100644 (file)
index 0000000..32f875e
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2002  David McCullough <davidm@snapgear.com>
+ * Copyright (C) 2003  Paul Mundt <lethal@linux-sh.org>
+ *
+ * Based on files with the following comments:
+ *
+ *           Copyright (C) 2000  Kazumoto Kojima
+ *
+ *           Modified for 7751 Solution Engine by
+ *           Ian da Silva and Jeremy Siegel, 2001.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <asm/machvec.h>
+#include <mach/secureedge5410.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <cpu/timer.h>
+
+unsigned short secureedge5410_ioport;
+
+/*
+ * EraseConfig handling functions
+ */
+static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id)
+{
+       ctrl_delay();   /* dummy read */
+
+       printk("SnapGear: erase switch interrupt!\n");
+
+       return IRQ_HANDLED;
+}
+
+static int __init eraseconfig_init(void)
+{
+       unsigned int irq = evt2irq(0x240);
+
+       printk("SnapGear: EraseConfig init\n");
+
+       /* Setup "EraseConfig" switch on external IRQ 0 */
+       if (request_irq(irq, eraseconfig_interrupt, IRQF_DISABLED,
+                               "Erase Config", NULL))
+               printk("SnapGear: failed to register IRQ%d for Reset witch\n",
+                               irq);
+       else
+               printk("SnapGear: registered EraseConfig switch on IRQ%d\n",
+                               irq);
+       return 0;
+}
+module_init(eraseconfig_init);
+
+/*
+ * Initialize IRQ setting
+ *
+ * IRL0 = erase switch
+ * IRL1 = eth0
+ * IRL2 = eth1
+ * IRL3 = crypto
+ */
+static void __init init_snapgear_IRQ(void)
+{
+       printk("Setup SnapGear IRQ/IPR ...\n");
+       /* enable individual interrupt mode for externals */
+       plat_irq_setup_pins(IRQ_MODE_IRQ);
+}
+
+/*
+ * The Machine Vector
+ */
+static struct sh_machine_vector mv_snapgear __initmv = {
+       .mv_name                = "SnapGear SecureEdge5410",
+       .mv_nr_irqs             = 72,
+       .mv_init_irq            = init_snapgear_IRQ,
+};
diff --git a/arch/sh/boards/mach-edosk7705/Makefile b/arch/sh/boards/mach-edosk7705/Makefile
deleted file mode 100644 (file)
index cd54acb..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the EDOSK7705 specific parts of the kernel
-#
-
-obj-y   := setup.o io.o
diff --git a/arch/sh/boards/mach-edosk7705/io.c b/arch/sh/boards/mach-edosk7705/io.c
deleted file mode 100644 (file)
index 5b9c57c..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * arch/sh/boards/renesas/edosk7705/io.c
- *
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routines for Hitachi EDOSK7705 board.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/io.h>
-#include <mach/edosk7705.h>
-#include <asm/addrspace.h>
-
-#define SMC_IOADDR     0xA2000000
-
-/* Map the Ethernet addresses as if it is at 0x300 - 0x320 */
-static unsigned long sh_edosk7705_isa_port2addr(unsigned long port)
-{
-       /*
-        * SMC91C96 registers are 4 byte aligned rather than the
-        * usual 2 byte!
-        */
-       if (port >= 0x300 && port < 0x320)
-               return SMC_IOADDR + ((port - 0x300) * 2);
-
-       maybebadio(port);
-       return port;
-}
-
-/* Trying to read / write bytes on odd-byte boundaries to the Ethernet
- * registers causes problems. So we bit-shift the value and read / write
- * in 2 byte chunks. Setting the low byte to 0 does not cause problems
- * now as odd byte writes are only made on the bit mask / interrupt
- * register. This may not be the case in future Mar-2003 SJD
- */
-unsigned char sh_edosk7705_inb(unsigned long port)
-{
-       if (port >= 0x300 && port < 0x320 && port & 0x01)
-               return __raw_readw(port - 1) >> 8;
-
-       return __raw_readb(sh_edosk7705_isa_port2addr(port));
-}
-
-void sh_edosk7705_outb(unsigned char value, unsigned long port)
-{
-       if (port >= 0x300 && port < 0x320 && port & 0x01) {
-               __raw_writew(((unsigned short)value << 8), port - 1);
-               return;
-       }
-
-       __raw_writeb(value, sh_edosk7705_isa_port2addr(port));
-}
-
-void sh_edosk7705_insb(unsigned long port, void *addr, unsigned long count)
-{
-       unsigned char *p = addr;
-
-       while (count--)
-               *p++ = sh_edosk7705_inb(port);
-}
-
-void sh_edosk7705_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-       unsigned char *p = (unsigned char *)addr;
-
-       while (count--)
-               sh_edosk7705_outb(*p++, port);
-}
diff --git a/arch/sh/boards/mach-edosk7705/setup.c b/arch/sh/boards/mach-edosk7705/setup.c
deleted file mode 100644 (file)
index d59225e..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * arch/sh/boards/renesas/edosk7705/setup.c
- *
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * Hitachi SolutionEngine Support.
- *
- * Modified for edosk7705 development
- * board by S. Dunn, 2003.
- */
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <asm/machvec.h>
-#include <mach/edosk7705.h>
-
-static void __init sh_edosk7705_init_irq(void)
-{
-       /* This is the Ethernet interrupt */
-       make_imask_irq(0x09);
-}
-
-/*
- * The Machine Vector
- */
-static struct sh_machine_vector mv_edosk7705 __initmv = {
-       .mv_name                = "EDOSK7705",
-       .mv_nr_irqs             = 80,
-
-       .mv_inb                 = sh_edosk7705_inb,
-       .mv_outb                = sh_edosk7705_outb,
-
-       .mv_insb                = sh_edosk7705_insb,
-       .mv_outsb               = sh_edosk7705_outsb,
-
-       .mv_init_irq            = sh_edosk7705_init_irq,
-};
index 2960c659020ee92e6c60c5c1d16d8d05ab73e267..acdafb0c6404a153cc482e46c0a17287f15ea26e 100644 (file)
@@ -54,7 +54,7 @@
 /*
  * map I/O ports to memory-mapped addresses
  */
-static unsigned long microdev_isa_port2addr(unsigned long offset)
+void __iomem *microdev_ioport_map(unsigned long offset, unsigned int len)
 {
        unsigned long result;
 
@@ -72,16 +72,6 @@ static unsigned long microdev_isa_port2addr(unsigned long offset)
                         *      Configuration Registers
                         */
                result = IO_SUPERIO_PHYS + (offset << 1);
-#if 0
-       } else if (offset == KBD_DATA_REG || offset == KBD_CNTL_REG ||
-                  offset == KBD_STATUS_REG) {
-                       /*
-                        *      SMSC FDC37C93xAPM SuperIO chip
-                        *
-                        *      PS/2 Keyboard + Mouse (ports 0x60 and 0x64).
-                        */
-               result = IO_SUPERIO_PHYS + (offset << 1);
-#endif
        } else if (((offset >= IO_IDE1_BASE) &&
                    (offset <  IO_IDE1_BASE + IO_IDE_EXTENT)) ||
                    (offset == IO_IDE1_MISC)) {
@@ -131,237 +121,5 @@ static unsigned long microdev_isa_port2addr(unsigned long offset)
                result = PVR;
        }
 
-       return result;
-}
-
-#define PORT2ADDR(x) (microdev_isa_port2addr(x))
-
-static inline void delay(void)
-{
-#if defined(CONFIG_PCI)
-       /* System board present, just make a dummy SRAM access.  (CS0 will be
-          mapped to PCI memory, probably good to avoid it.) */
-       __raw_readw(0xa6800000);
-#else
-       /* CS0 will be mapped to flash, ROM etc so safe to access it. */
-       __raw_readw(0xa0000000);
-#endif
-}
-
-unsigned char microdev_inb(unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO)
-               return microdev_pci_inb(port);
-#endif
-       return *(volatile unsigned char*)PORT2ADDR(port);
-}
-
-unsigned short microdev_inw(unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO)
-               return microdev_pci_inw(port);
-#endif
-       return *(volatile unsigned short*)PORT2ADDR(port);
-}
-
-unsigned int microdev_inl(unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO)
-               return microdev_pci_inl(port);
-#endif
-       return *(volatile unsigned int*)PORT2ADDR(port);
-}
-
-void microdev_outw(unsigned short b, unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO) {
-               microdev_pci_outw(b, port);
-               return;
-       }
-#endif
-       *(volatile unsigned short*)PORT2ADDR(port) = b;
-}
-
-void microdev_outb(unsigned char b, unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO) {
-               microdev_pci_outb(b, port);
-               return;
-       }
-#endif
-
-       /*
-        *      There is a board feature with the current SH4-202 MicroDev in
-        *      that the 2 byte enables (nBE0 and nBE1) are tied together (and
-        *      to the Chip Select Line (Ethernet_CS)). Due to this connectivity,
-        *      it is not possible to safely perform 8-bit writes to the
-        *      Ethernet registers, as 16-bits will be consumed from the Data
-        *      lines (corrupting the other byte).  Hence, this function is
-        *      written to implement 16-bit read/modify/write for all byte-wide
-        *      accesses.
-        *
-        *      Note: there is no problem with byte READS (even or odd).
-        *
-        *                      Sean McGoogan - 16th June 2003.
-        */
-       if ((port >= IO_LAN91C111_BASE) &&
-           (port <  IO_LAN91C111_BASE + IO_LAN91C111_EXTENT)) {
-                       /*
-                        * Then are trying to perform a byte-write to the
-                        * LAN91C111.  This needs special care.
-                        */
-               if (port % 2 == 1) {    /* is the port odd ? */
-                       /* unset bit-0, i.e. make even */
-                       const unsigned long evenPort = port-1;
-                       unsigned short word;
-
-                       /*
-                        * do a 16-bit read/write to write to 'port',
-                        * preserving even byte.
-                        *
-                        *      Even addresses are bits 0-7
-                        *      Odd  addresses are bits 8-15
-                        */
-                       word = microdev_inw(evenPort);
-                       word = (word & 0xffu) | (b << 8);
-                       microdev_outw(word, evenPort);
-               } else {
-                       /* else, we are trying to do an even byte write */
-                       unsigned short word;
-
-                       /*
-                        * do a 16-bit read/write to write to 'port',
-                        * preserving odd byte.
-                        *
-                        *      Even addresses are bits 0-7
-                        *      Odd  addresses are bits 8-15
-                        */
-                       word = microdev_inw(port);
-                       word = (word & 0xff00u) | (b);
-                       microdev_outw(word, port);
-               }
-       } else {
-               *(volatile unsigned char*)PORT2ADDR(port) = b;
-       }
-}
-
-void microdev_outl(unsigned int b, unsigned long port)
-{
-#ifdef CONFIG_PCI
-       if (port >= PCIBIOS_MIN_IO) {
-               microdev_pci_outl(b, port);
-               return;
-       }
-#endif
-       *(volatile unsigned int*)PORT2ADDR(port) = b;
-}
-
-unsigned char microdev_inb_p(unsigned long port)
-{
-       unsigned char v = microdev_inb(port);
-       delay();
-       return v;
-}
-
-unsigned short microdev_inw_p(unsigned long port)
-{
-       unsigned short v = microdev_inw(port);
-       delay();
-       return v;
-}
-
-unsigned int microdev_inl_p(unsigned long port)
-{
-       unsigned int v = microdev_inl(port);
-       delay();
-       return v;
-}
-
-void microdev_outb_p(unsigned char b, unsigned long port)
-{
-       microdev_outb(b, port);
-       delay();
-}
-
-void microdev_outw_p(unsigned short b, unsigned long port)
-{
-       microdev_outw(b, port);
-       delay();
-}
-
-void microdev_outl_p(unsigned int b, unsigned long port)
-{
-       microdev_outl(b, port);
-       delay();
-}
-
-void microdev_insb(unsigned long port, void *buffer, unsigned long count)
-{
-       volatile unsigned char *port_addr;
-       unsigned char *buf = buffer;
-
-       port_addr = (volatile unsigned char *)PORT2ADDR(port);
-
-       while (count--)
-               *buf++ = *port_addr;
-}
-
-void microdev_insw(unsigned long port, void *buffer, unsigned long count)
-{
-       volatile unsigned short *port_addr;
-       unsigned short *buf = buffer;
-
-       port_addr = (volatile unsigned short *)PORT2ADDR(port);
-
-       while (count--)
-               *buf++ = *port_addr;
-}
-
-void microdev_insl(unsigned long port, void *buffer, unsigned long count)
-{
-       volatile unsigned long *port_addr;
-       unsigned int *buf = buffer;
-
-       port_addr = (volatile unsigned long *)PORT2ADDR(port);
-
-       while (count--)
-               *buf++ = *port_addr;
-}
-
-void microdev_outsb(unsigned long port, const void *buffer, unsigned long count)
-{
-       volatile unsigned char *port_addr;
-       const unsigned char *buf = buffer;
-
-       port_addr = (volatile unsigned char *)PORT2ADDR(port);
-
-       while (count--)
-               *port_addr = *buf++;
-}
-
-void microdev_outsw(unsigned long port, const void *buffer, unsigned long count)
-{
-       volatile unsigned short *port_addr;
-       const unsigned short *buf = buffer;
-
-       port_addr = (volatile unsigned short *)PORT2ADDR(port);
-
-       while (count--)
-               *port_addr = *buf++;
-}
-
-void microdev_outsl(unsigned long port, const void *buffer, unsigned long count)
-{
-       volatile unsigned long *port_addr;
-       const unsigned int *buf = buffer;
-
-       port_addr = (volatile unsigned long *)PORT2ADDR(port);
-
-       while (count--)
-               *port_addr = *buf++;
+       return (void __iomem *)result;
 }
index d1df2a4fb9b885913d38a90c49ff44f7bb0ace50..d8a747291e03ed82a829e20e4e779013881f1197 100644 (file)
@@ -195,27 +195,6 @@ device_initcall(microdev_devices_setup);
 static struct sh_machine_vector mv_sh4202_microdev __initmv = {
        .mv_name                = "SH4-202 MicroDev",
        .mv_nr_irqs             = 72,
-
-       .mv_inb                 = microdev_inb,
-       .mv_inw                 = microdev_inw,
-       .mv_inl                 = microdev_inl,
-       .mv_outb                = microdev_outb,
-       .mv_outw                = microdev_outw,
-       .mv_outl                = microdev_outl,
-
-       .mv_inb_p               = microdev_inb_p,
-       .mv_inw_p               = microdev_inw_p,
-       .mv_inl_p               = microdev_inl_p,
-       .mv_outb_p              = microdev_outb_p,
-       .mv_outw_p              = microdev_outw_p,
-       .mv_outl_p              = microdev_outl_p,
-
-       .mv_insb                = microdev_insb,
-       .mv_insw                = microdev_insw,
-       .mv_insl                = microdev_insl,
-       .mv_outsb               = microdev_outsb,
-       .mv_outsw               = microdev_outsw,
-       .mv_outsl               = microdev_outsl,
-
+       .mv_ioport_map          = microdev_ioport_map,
        .mv_init_irq            = init_microdev_irq,
 };
index 63e7ed699f39b3c41d8578daa8b57ce31807c689..5c9eaa0535b935c5f90bde958b0ca79724e1dcc2 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the 7206 SolutionEngine specific parts of the kernel
 #
 
-obj-y   := setup.o io.o irq.o
+obj-y   := setup.o irq.o
diff --git a/arch/sh/boards/mach-se/7206/io.c b/arch/sh/boards/mach-se/7206/io.c
deleted file mode 100644 (file)
index adadc77..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/* $Id: io.c,v 1.5 2004/02/22 23:08:43 kkojima Exp $
- *
- * linux/arch/sh/boards/se/7206/io.c
- *
- * Copyright (C) 2006 Yoshinori Sato
- *
- * I/O routine for Hitachi 7206 SolutionEngine.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <asm/io.h>
-#include <mach-se/mach/se7206.h>
-
-
-static inline void delay(void)
-{
-       __raw_readw(0x20000000);  /* P2 ROM Area */
-}
-
-/* MS7750 requires special versions of in*, out* routines, since
-   PC-like io ports are located at upper half byte of 16-bit word which
-   can be accessed only with 16-bit wide.  */
-
-static inline volatile __u16 *
-port2adr(unsigned int port)
-{
-       if (port >= 0x2000 && port < 0x2020)
-               return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-       else if (port >= 0x300 && port < 0x310)
-               return (volatile __u16 *) (PA_SMSC + (port - 0x300));
-
-       return (volatile __u16 *)port;
-}
-
-unsigned char se7206_inb(unsigned long port)
-{
-       return (*port2adr(port)) & 0xff;
-}
-
-unsigned char se7206_inb_p(unsigned long port)
-{
-       unsigned long v;
-
-       v = (*port2adr(port)) & 0xff;
-       delay();
-       return v;
-}
-
-unsigned short se7206_inw(unsigned long port)
-{
-       return *port2adr(port);
-}
-
-void se7206_outb(unsigned char value, unsigned long port)
-{
-       *(port2adr(port)) = value;
-}
-
-void se7206_outb_p(unsigned char value, unsigned long port)
-{
-       *(port2adr(port)) = value;
-       delay();
-}
-
-void se7206_outw(unsigned short value, unsigned long port)
-{
-       *port2adr(port) = value;
-}
-
-void se7206_insb(unsigned long port, void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       __u8 *ap = addr;
-
-       while (count--)
-               *ap++ = *p;
-}
-
-void se7206_insw(unsigned long port, void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       __u16 *ap = addr;
-       while (count--)
-               *ap++ = *p;
-}
-
-void se7206_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       const __u8 *ap = addr;
-
-       while (count--)
-               *p = *ap++;
-}
-
-void se7206_outsw(unsigned long port, const void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       const __u16 *ap = addr;
-       while (count--)
-               *p = *ap++;
-}
index 883b21eacaa686d00efbf822911dac79e6e220d5..d961949600fd462199f3d9706e86371e815e7b1b 100644 (file)
@@ -139,11 +139,13 @@ void __init init_se7206_IRQ(void)
        make_se7206_irq(IRQ0_IRQ); /* SMC91C111 */
        make_se7206_irq(IRQ1_IRQ); /* ATA */
        make_se7206_irq(IRQ3_IRQ); /* SLOT / PCM */
-       __raw_writew(inw(INTC_ICR1) | 0x000b ,INTC_ICR1 ) ; /* ICR1 */
+
+       __raw_writew(__raw_readw(INTC_ICR1) | 0x000b, INTC_ICR); /* ICR1 */
 
        /* FPGA System register setup*/
        __raw_writew(0x0000,INTSTS0); /* Clear INTSTS0 */
        __raw_writew(0x0000,INTSTS1); /* Clear INTSTS1 */
+
        /* IRQ0=LAN, IRQ1=ATA, IRQ3=SLT,PCM */
        __raw_writew(0x0001,INTSEL);
 }
index 8f5c65d43d1d85a6e1db054cd5f065ee3aa72119..7f4871c71a01813dbd11882d9c55469d46359ce0 100644 (file)
@@ -86,20 +86,5 @@ __initcall(se7206_devices_setup);
 static struct sh_machine_vector mv_se __initmv = {
        .mv_name                = "SolutionEngine",
        .mv_nr_irqs             = 256,
-       .mv_inb                 = se7206_inb,
-       .mv_inw                 = se7206_inw,
-       .mv_outb                = se7206_outb,
-       .mv_outw                = se7206_outw,
-
-       .mv_inb_p               = se7206_inb_p,
-       .mv_inw_p               = se7206_inw,
-       .mv_outb_p              = se7206_outb_p,
-       .mv_outw_p              = se7206_outw,
-
-       .mv_insb                = se7206_insb,
-       .mv_insw                = se7206_insw,
-       .mv_outsb               = se7206_outsb,
-       .mv_outsw               = se7206_outsw,
-
        .mv_init_irq            = init_se7206_IRQ,
 };
index 8e624b06d5ea67efc746ecab0716485d9a4742bc..43ea14feef51094d032c5b7eec98b35deff925f8 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the 770x SolutionEngine specific parts of the kernel
 #
 
-obj-y   := setup.o io.o irq.o
+obj-y   := setup.o irq.o
diff --git a/arch/sh/boards/mach-se/770x/io.c b/arch/sh/boards/mach-se/770x/io.c
deleted file mode 100644 (file)
index 28833c8..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * I/O routine for Hitachi SolutionEngine.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <asm/io.h>
-#include <mach-se/mach/se.h>
-
-/* MS7750 requires special versions of in*, out* routines, since
-   PC-like io ports are located at upper half byte of 16-bit word which
-   can be accessed only with 16-bit wide.  */
-
-static inline volatile __u16 *
-port2adr(unsigned int port)
-{
-       if (port & 0xff000000)
-               return ( volatile __u16 *) port;
-       if (port >= 0x2000)
-               return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-       else if (port >= 0x1000)
-               return (volatile __u16 *) (PA_83902 + (port << 1));
-       else
-               return (volatile __u16 *) (PA_SUPERIO + (port << 1));
-}
-
-static inline int
-shifted_port(unsigned long port)
-{
-       /* For IDE registers, value is not shifted */
-       if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
-               return 0;
-       else
-               return 1;
-}
-
-unsigned char se_inb(unsigned long port)
-{
-       if (shifted_port(port))
-               return (*port2adr(port) >> 8);
-       else
-               return (*port2adr(port))&0xff;
-}
-
-unsigned char se_inb_p(unsigned long port)
-{
-       unsigned long v;
-
-       if (shifted_port(port))
-               v = (*port2adr(port) >> 8);
-       else
-               v = (*port2adr(port))&0xff;
-       ctrl_delay();
-       return v;
-}
-
-unsigned short se_inw(unsigned long port)
-{
-       if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-unsigned int se_inl(unsigned long port)
-{
-       maybebadio(port);
-       return 0;
-}
-
-void se_outb(unsigned char value, unsigned long port)
-{
-       if (shifted_port(port))
-               *(port2adr(port)) = value << 8;
-       else
-               *(port2adr(port)) = value;
-}
-
-void se_outb_p(unsigned char value, unsigned long port)
-{
-       if (shifted_port(port))
-               *(port2adr(port)) = value << 8;
-       else
-               *(port2adr(port)) = value;
-       ctrl_delay();
-}
-
-void se_outw(unsigned short value, unsigned long port)
-{
-       if (port >= 0x2000)
-               *port2adr(port) = value;
-       else
-               maybebadio(port);
-}
-
-void se_outl(unsigned int value, unsigned long port)
-{
-       maybebadio(port);
-}
-
-void se_insb(unsigned long port, void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       __u8 *ap = addr;
-
-       if (shifted_port(port)) {
-               while (count--)
-                       *ap++ = *p >> 8;
-       } else {
-               while (count--)
-                       *ap++ = *p;
-       }
-}
-
-void se_insw(unsigned long port, void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       __u16 *ap = addr;
-       while (count--)
-               *ap++ = *p;
-}
-
-void se_insl(unsigned long port, void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
-
-void se_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       const __u8 *ap = addr;
-
-       if (shifted_port(port)) {
-               while (count--)
-                       *p = *ap++ << 8;
-       } else {
-               while (count--)
-                       *p = *ap++;
-       }
-}
-
-void se_outsw(unsigned long port, const void *addr, unsigned long count)
-{
-       volatile __u16 *p = port2adr(port);
-       const __u16 *ap = addr;
-
-       while (count--)
-               *p = *ap++;
-}
-
-void se_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
index 66d39d1b0901de5a9b6da4c7fb7978223b18b502..31330c65c0cec9aa1b78abb69e5bcb95c9c4cd80 100644 (file)
@@ -195,27 +195,5 @@ static struct sh_machine_vector mv_se __initmv = {
 #elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
        .mv_nr_irqs             = 104,
 #endif
-
-       .mv_inb                 = se_inb,
-       .mv_inw                 = se_inw,
-       .mv_inl                 = se_inl,
-       .mv_outb                = se_outb,
-       .mv_outw                = se_outw,
-       .mv_outl                = se_outl,
-
-       .mv_inb_p               = se_inb_p,
-       .mv_inw_p               = se_inw,
-       .mv_inl_p               = se_inl,
-       .mv_outb_p              = se_outb_p,
-       .mv_outw_p              = se_outw,
-       .mv_outl_p              = se_outl,
-
-       .mv_insb                = se_insb,
-       .mv_insw                = se_insw,
-       .mv_insl                = se_insl,
-       .mv_outsb               = se_outsb,
-       .mv_outsw               = se_outsw,
-       .mv_outsl               = se_outsl,
-
        .mv_init_irq            = init_se_IRQ,
 };
index e6f4341bfe6eaa0467e60dfb56ae08688ea5a9c0..a338fd9d503944f84b4e84b5a3a3e7cccc4a5fcb 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for the 7751 SolutionEngine specific parts of the kernel
 #
 
-obj-y   := setup.o io.o irq.o
+obj-y   := setup.o irq.o
diff --git a/arch/sh/boards/mach-se/7751/io.c b/arch/sh/boards/mach-se/7751/io.c
deleted file mode 100644 (file)
index 6e75bd4..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routine for Hitachi 7751 SolutionEngine.
- *
- * Initial version only to support LAN access; some
- * placeholder code from io_se.c left in with the
- * expectation of later SuperIO and PCMCIA access.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include <mach-se/mach/se7751.h>
-#include <asm/addrspace.h>
-
-static inline volatile u16 *port2adr(unsigned int port)
-{
-       if (port >= 0x2000)
-               return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-       maybebadio((unsigned long)port);
-       return (volatile __u16*)port;
-}
-
-/*
- * General outline: remap really low stuff [eventually] to SuperIO,
- * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
- * is mapped through the PCI IO window.  Stuff with high bits (PXSEG)
- * should be way beyond the window, and is used  w/o translation for
- * compatibility.
- */
-unsigned char sh7751se_inb(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned char *)port;
-       else
-               return (*port2adr(port)) & 0xff;
-}
-
-unsigned char sh7751se_inb_p(unsigned long port)
-{
-       unsigned char v;
-
-        if (PXSEG(port))
-                v = *(volatile unsigned char *)port;
-       else
-               v = (*port2adr(port)) & 0xff;
-       ctrl_delay();
-       return v;
-}
-
-unsigned short sh7751se_inw(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned short *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-unsigned int sh7751se_inl(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned long *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-void sh7751se_outb(unsigned char value, unsigned long port)
-{
-
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-       else
-               *(port2adr(port)) = value;
-}
-
-void sh7751se_outb_p(unsigned char value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-       else
-               *(port2adr(port)) = value;
-       ctrl_delay();
-}
-
-void sh7751se_outw(unsigned short value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned short *)port = value;
-       else if (port >= 0x2000)
-               *port2adr(port) = value;
-       else
-               maybebadio(port);
-}
-
-void sh7751se_outl(unsigned int value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned long *)port = value;
-       else
-               maybebadio(port);
-}
-
-void sh7751se_insl(unsigned long port, void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
-
-void sh7751se_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
index 50572512e3e84a6db630114a57415153fd4e0506..9fbc51beb1812dfafd10a91cf7b6c02c1cabfdce 100644 (file)
@@ -56,23 +56,5 @@ __initcall(se7751_devices_setup);
 static struct sh_machine_vector mv_7751se __initmv = {
        .mv_name                = "7751 SolutionEngine",
        .mv_nr_irqs             = 72,
-
-       .mv_inb                 = sh7751se_inb,
-       .mv_inw                 = sh7751se_inw,
-       .mv_inl                 = sh7751se_inl,
-       .mv_outb                = sh7751se_outb,
-       .mv_outw                = sh7751se_outw,
-       .mv_outl                = sh7751se_outl,
-
-       .mv_inb_p               = sh7751se_inb_p,
-       .mv_inw_p               = sh7751se_inw,
-       .mv_inl_p               = sh7751se_inl,
-       .mv_outb_p              = sh7751se_outb_p,
-       .mv_outw_p              = sh7751se_outw,
-       .mv_outl_p              = sh7751se_outl,
-
-       .mv_insl                = sh7751se_insl,
-       .mv_outsl               = sh7751se_outsl,
-
        .mv_init_irq            = init_7751se_IRQ,
 };
diff --git a/arch/sh/boards/mach-snapgear/Makefile b/arch/sh/boards/mach-snapgear/Makefile
deleted file mode 100644 (file)
index d2d2f4b..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the SnapGear specific parts of the kernel
-#
-
-obj-y   := setup.o io.o
diff --git a/arch/sh/boards/mach-snapgear/io.c b/arch/sh/boards/mach-snapgear/io.c
deleted file mode 100644 (file)
index 476650e..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2002  David McCullough <davidm@snapgear.com>
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routine for Hitachi 7751 SolutionEngine.
- *
- * Initial version only to support LAN access; some
- * placeholder code from io_se.c left in with the
- * expectation of later SuperIO and PCMCIA access.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include <asm/addrspace.h>
-
-#ifdef CONFIG_SH_SECUREEDGE5410
-unsigned short secureedge5410_ioport;
-#endif
-
-static inline volatile __u16 *port2adr(unsigned int port)
-{
-       maybebadio((unsigned long)port);
-       return (volatile __u16*)port;
-}
-
-/*
- * General outline: remap really low stuff [eventually] to SuperIO,
- * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
- * is mapped through the PCI IO window.  Stuff with high bits (PXSEG)
- * should be way beyond the window, and is used  w/o translation for
- * compatibility.
- */
-unsigned char snapgear_inb(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned char *)port;
-       else
-               return (*port2adr(port)) & 0xff;
-}
-
-unsigned char snapgear_inb_p(unsigned long port)
-{
-       unsigned char v;
-
-       if (PXSEG(port))
-               v = *(volatile unsigned char *)port;
-       else
-               v = (*port2adr(port))&0xff;
-       ctrl_delay();
-       return v;
-}
-
-unsigned short snapgear_inw(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned short *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-unsigned int snapgear_inl(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned long *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-void snapgear_outb(unsigned char value, unsigned long port)
-{
-
-       if (PXSEG(port))
-               *(volatile unsigned char *)port = value;
-       else
-               *(port2adr(port)) = value;
-}
-
-void snapgear_outb_p(unsigned char value, unsigned long port)
-{
-       if (PXSEG(port))
-               *(volatile unsigned char *)port = value;
-       else
-               *(port2adr(port)) = value;
-       ctrl_delay();
-}
-
-void snapgear_outw(unsigned short value, unsigned long port)
-{
-       if (PXSEG(port))
-               *(volatile unsigned short *)port = value;
-       else if (port >= 0x2000)
-               *port2adr(port) = value;
-       else
-               maybebadio(port);
-}
-
-void snapgear_outl(unsigned int value, unsigned long port)
-{
-       if (PXSEG(port))
-               *(volatile unsigned long *)port = value;
-       else
-               maybebadio(port);
-}
-
-void snapgear_insl(unsigned long port, void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
-
-void snapgear_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
diff --git a/arch/sh/boards/mach-snapgear/setup.c b/arch/sh/boards/mach-snapgear/setup.c
deleted file mode 100644 (file)
index 331745d..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * linux/arch/sh/boards/snapgear/setup.c
- *
- * Copyright (C) 2002  David McCullough <davidm@snapgear.com>
- * Copyright (C) 2003  Paul Mundt <lethal@linux-sh.org>
- *
- * Based on files with the following comments:
- *
- *           Copyright (C) 2000  Kazumoto Kojima
- *
- *           Modified for 7751 Solution Engine by
- *           Ian da Silva and Jeremy Siegel, 2001.
- */
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <asm/machvec.h>
-#include <mach/snapgear.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <cpu/timer.h>
-
-/*
- * EraseConfig handling functions
- */
-
-static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id)
-{
-       (void)__raw_readb(0xb8000000);  /* dummy read */
-
-       printk("SnapGear: erase switch interrupt!\n");
-
-       return IRQ_HANDLED;
-}
-
-static int __init eraseconfig_init(void)
-{
-       printk("SnapGear: EraseConfig init\n");
-       /* Setup "EraseConfig" switch on external IRQ 0 */
-       if (request_irq(IRL0_IRQ, eraseconfig_interrupt, IRQF_DISABLED,
-                               "Erase Config", NULL))
-               printk("SnapGear: failed to register IRQ%d for Reset witch\n",
-                               IRL0_IRQ);
-       else
-               printk("SnapGear: registered EraseConfig switch on IRQ%d\n",
-                               IRL0_IRQ);
-       return(0);
-}
-
-module_init(eraseconfig_init);
-
-/****************************************************************************/
-/*
- * Initialize IRQ setting
- *
- * IRL0 = erase switch
- * IRL1 = eth0
- * IRL2 = eth1
- * IRL3 = crypto
- */
-
-static void __init init_snapgear_IRQ(void)
-{
-       printk("Setup SnapGear IRQ/IPR ...\n");
-       /* enable individual interrupt mode for externals */
-       plat_irq_setup_pins(IRQ_MODE_IRQ);
-}
-
-/*
- * The Machine Vector
- */
-static struct sh_machine_vector mv_snapgear __initmv = {
-       .mv_name                = "SnapGear SecureEdge5410",
-       .mv_nr_irqs             = 72,
-
-       .mv_inb                 = snapgear_inb,
-       .mv_inw                 = snapgear_inw,
-       .mv_inl                 = snapgear_inl,
-       .mv_outb                = snapgear_outb,
-       .mv_outw                = snapgear_outw,
-       .mv_outl                = snapgear_outl,
-
-       .mv_inb_p               = snapgear_inb_p,
-       .mv_inw_p               = snapgear_inw,
-       .mv_inl_p               = snapgear_inl,
-       .mv_outb_p              = snapgear_outb_p,
-       .mv_outw_p              = snapgear_outw,
-       .mv_outl_p              = snapgear_outl,
-
-       .mv_init_irq            = init_snapgear_IRQ,
-};
diff --git a/arch/sh/boards/mach-systemh/Makefile b/arch/sh/boards/mach-systemh/Makefile
deleted file mode 100644 (file)
index 2cc6a23..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# Makefile for the SystemH specific parts of the kernel
-#
-
-obj-y   := setup.o irq.o io.o
-
-# XXX: This wants to be consolidated in arch/sh/drivers/pci, and more
-# importantly, with the generic sh7751_pcic_init() code. For now, we'll
-# just abuse the hell out of kbuild, because we can..
-
-obj-$(CONFIG_PCI) += pci.o
-pci-y := ../../se/7751/pci.o
-
diff --git a/arch/sh/boards/mach-systemh/io.c b/arch/sh/boards/mach-systemh/io.c
deleted file mode 100644 (file)
index 15577ff..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * linux/arch/sh/boards/renesas/systemh/io.c
- *
- * Copyright (C) 2001  Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routine for Hitachi 7751 Systemh.
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <mach/systemh7751.h>
-#include <asm/addrspace.h>
-#include <asm/io.h>
-
-#define ETHER_IOMAP(adr) (0xB3000000 + (adr)) /*map to 16bits access area
-                                                of smc lan chip*/
-static inline volatile __u16 *
-port2adr(unsigned int port)
-{
-       if (port >= 0x2000)
-               return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-       maybebadio((unsigned long)port);
-       return (volatile __u16*)port;
-}
-
-/*
- * General outline: remap really low stuff [eventually] to SuperIO,
- * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
- * is mapped through the PCI IO window.  Stuff with high bits (PXSEG)
- * should be way beyond the window, and is used  w/o translation for
- * compatibility.
- */
-unsigned char sh7751systemh_inb(unsigned long port)
-{
-       if (PXSEG(port))
-               return *(volatile unsigned char *)port;
-       else if (port <= 0x3F1)
-               return *(volatile unsigned char *)ETHER_IOMAP(port);
-       else
-               return (*port2adr(port))&0xff;
-}
-
-unsigned char sh7751systemh_inb_p(unsigned long port)
-{
-       unsigned char v;
-
-        if (PXSEG(port))
-                v = *(volatile unsigned char *)port;
-       else if (port <= 0x3F1)
-               v = *(volatile unsigned char *)ETHER_IOMAP(port);
-       else
-               v = (*port2adr(port))&0xff;
-       ctrl_delay();
-       return v;
-}
-
-unsigned short sh7751systemh_inw(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned short *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else if (port <= 0x3F1)
-               return *(volatile unsigned int *)ETHER_IOMAP(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-unsigned int sh7751systemh_inl(unsigned long port)
-{
-        if (PXSEG(port))
-                return *(volatile unsigned long *)port;
-       else if (port >= 0x2000)
-               return *port2adr(port);
-       else if (port <= 0x3F1)
-               return *(volatile unsigned int *)ETHER_IOMAP(port);
-       else
-               maybebadio(port);
-       return 0;
-}
-
-void sh7751systemh_outb(unsigned char value, unsigned long port)
-{
-
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-       else if (port <= 0x3F1)
-               *(volatile unsigned char *)ETHER_IOMAP(port) = value;
-       else
-               *(port2adr(port)) = value;
-}
-
-void sh7751systemh_outb_p(unsigned char value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned char *)port = value;
-       else if (port <= 0x3F1)
-               *(volatile unsigned char *)ETHER_IOMAP(port) = value;
-       else
-               *(port2adr(port)) = value;
-       ctrl_delay();
-}
-
-void sh7751systemh_outw(unsigned short value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned short *)port = value;
-       else if (port >= 0x2000)
-               *port2adr(port) = value;
-       else if (port <= 0x3F1)
-               *(volatile unsigned short *)ETHER_IOMAP(port) = value;
-       else
-               maybebadio(port);
-}
-
-void sh7751systemh_outl(unsigned int value, unsigned long port)
-{
-        if (PXSEG(port))
-                *(volatile unsigned long *)port = value;
-       else
-               maybebadio(port);
-}
-
-void sh7751systemh_insb(unsigned long port, void *addr, unsigned long count)
-{
-       unsigned char *p = addr;
-       while (count--) *p++ = sh7751systemh_inb(port);
-}
-
-void sh7751systemh_insw(unsigned long port, void *addr, unsigned long count)
-{
-       unsigned short *p = addr;
-       while (count--) *p++ = sh7751systemh_inw(port);
-}
-
-void sh7751systemh_insl(unsigned long port, void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
-
-void sh7751systemh_outsb(unsigned long port, const void *addr, unsigned long count)
-{
-       unsigned char *p = (unsigned char*)addr;
-       while (count--) sh7751systemh_outb(*p++, port);
-}
-
-void sh7751systemh_outsw(unsigned long port, const void *addr, unsigned long count)
-{
-       unsigned short *p = (unsigned short*)addr;
-       while (count--) sh7751systemh_outw(*p++, port);
-}
-
-void sh7751systemh_outsl(unsigned long port, const void *addr, unsigned long count)
-{
-       maybebadio(port);
-}
diff --git a/arch/sh/boards/mach-systemh/irq.c b/arch/sh/boards/mach-systemh/irq.c
deleted file mode 100644 (file)
index e5ee13a..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * linux/arch/sh/boards/renesas/systemh/irq.c
- *
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * Hitachi SystemH Support.
- *
- * Modified for 7751 SystemH by
- * Jonathan Short.
- */
-
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-
-#include <mach/systemh7751.h>
-#include <asm/smc37c93x.h>
-
-/* address of external interrupt mask register
- * address must be set prior to use these (maybe in init_XXX_irq())
- * XXX : is it better to use .config than specifying it in code? */
-static unsigned long *systemh_irq_mask_register = (unsigned long *)0xB3F10004;
-static unsigned long *systemh_irq_request_register = (unsigned long *)0xB3F10000;
-
-static void disable_systemh_irq(struct irq_data *data)
-{
-       unsigned long val, mask = 0x01 << 1;
-
-       /* Clear the "irq"th bit in the mask and set it in the request */
-       val = __raw_readl((unsigned long)systemh_irq_mask_register);
-       val &= ~mask;
-       __raw_writel(val, (unsigned long)systemh_irq_mask_register);
-
-       val = __raw_readl((unsigned long)systemh_irq_request_register);
-       val |= mask;
-       __raw_writel(val, (unsigned long)systemh_irq_request_register);
-}
-
-static void enable_systemh_irq(struct irq_data *data)
-{
-       unsigned long val, mask = 0x01 << 1;
-
-       /* Set "irq"th bit in the mask register */
-       val = __raw_readl((unsigned long)systemh_irq_mask_register);
-       val |= mask;
-       __raw_writel(val, (unsigned long)systemh_irq_mask_register);
-}
-
-static struct irq_chip systemh_irq_type = {
-       .name           = "SystemH Register",
-       .irq_unmask     = enable_systemh_irq,
-       .irq_mask       = disable_systemh_irq,
-};
-
-void make_systemh_irq(unsigned int irq)
-{
-       disable_irq_nosync(irq);
-       set_irq_chip_and_handler(irq, &systemh_irq_type, handle_level_irq);
-       disable_systemh_irq(irq_get_irq_data(irq));
-}
diff --git a/arch/sh/boards/mach-systemh/setup.c b/arch/sh/boards/mach-systemh/setup.c
deleted file mode 100644 (file)
index 219fd80..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * linux/arch/sh/boards/renesas/systemh/setup.c
- *
- * Copyright (C) 2000  Kazumoto Kojima
- * Copyright (C) 2003  Paul Mundt
- *
- * Hitachi SystemH Support.
- *
- * Modified for 7751 SystemH by Jonathan Short.
- *
- * Rewritten for 2.6 by Paul Mundt.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/init.h>
-#include <asm/machvec.h>
-#include <mach/systemh7751.h>
-
-extern void make_systemh_irq(unsigned int irq);
-
-/*
- * Initialize IRQ setting
- */
-static void __init sh7751systemh_init_irq(void)
-{
-       make_systemh_irq(0xb);  /* Ethernet interrupt */
-}
-
-static struct sh_machine_vector mv_7751systemh __initmv = {
-       .mv_name                = "7751 SystemH",
-       .mv_nr_irqs             = 72,
-
-       .mv_inb                 = sh7751systemh_inb,
-       .mv_inw                 = sh7751systemh_inw,
-       .mv_inl                 = sh7751systemh_inl,
-       .mv_outb                = sh7751systemh_outb,
-       .mv_outw                = sh7751systemh_outw,
-       .mv_outl                = sh7751systemh_outl,
-
-       .mv_inb_p               = sh7751systemh_inb_p,
-       .mv_inw_p               = sh7751systemh_inw,
-       .mv_inl_p               = sh7751systemh_inl,
-       .mv_outb_p              = sh7751systemh_outb_p,
-       .mv_outw_p              = sh7751systemh_outw,
-       .mv_outl_p              = sh7751systemh_outl,
-
-       .mv_insb                = sh7751systemh_insb,
-       .mv_insw                = sh7751systemh_insw,
-       .mv_insl                = sh7751systemh_insl,
-       .mv_outsb               = sh7751systemh_outsb,
-       .mv_outsw               = sh7751systemh_outsw,
-       .mv_outsl               = sh7751systemh_outsl,
-
-       .mv_init_irq            = sh7751systemh_init_irq,
-};
diff --git a/arch/sh/configs/secureedge5410_defconfig b/arch/sh/configs/secureedge5410_defconfig
new file mode 100644 (file)
index 0000000..7eae4e5
--- /dev/null
@@ -0,0 +1,63 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_SWAP is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_SLAB=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_CPU_SUBTYPE_SH7751R=y
+CONFIG_MEMORY_SIZE=0x01000000
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_SH_SECUREEDGE5410=y
+CONFIG_SH_DMA=y
+CONFIG_SH_DMA_API=y
+CONFIG_PCI=y
+CONFIG_NET=y
+CONFIG_INET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_MTD=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK_RO=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
+# CONFIG_MTD_CFI_I2 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_PLATRAM=y
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_MISC_DEVICES is not set
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_PCI=y
+CONFIG_8139CP=y
+CONFIG_8139TOO=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1302=y
+CONFIG_EXT2_FS=y
+# CONFIG_DNOTIFY is not set
+CONFIG_TMPFS=y
+CONFIG_CRAMFS=y
+CONFIG_ROMFS_FS=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff --git a/arch/sh/configs/snapgear_defconfig b/arch/sh/configs/snapgear_defconfig
deleted file mode 100644 (file)
index 7eae4e5..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_SYSCTL_SYSCALL is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_SLAB=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_CPU_SUBTYPE_SH7751R=y
-CONFIG_MEMORY_SIZE=0x01000000
-CONFIG_FLATMEM_MANUAL=y
-CONFIG_SH_SECUREEDGE5410=y
-CONFIG_SH_DMA=y
-CONFIG_SH_DMA_API=y
-CONFIG_PCI=y
-CONFIG_NET=y
-CONFIG_INET=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK_RO=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_ADV_OPTIONS=y
-CONFIG_MTD_CFI_GEOMETRY=y
-# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_4 is not set
-# CONFIG_MTD_CFI_I2 is not set
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_PLATRAM=y
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_NET_PCI=y
-CONFIG_8139CP=y
-CONFIG_8139TOO=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_SH_SCI=y
-CONFIG_SERIAL_SH_SCI_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_DS1302=y
-CONFIG_EXT2_FS=y
-# CONFIG_DNOTIFY is not set
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_ROMFS_FS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
diff --git a/arch/sh/configs/systemh_defconfig b/arch/sh/configs/systemh_defconfig
deleted file mode 100644 (file)
index b58dfc5..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_SYSCTL_SYSCALL is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_CPU_SUBTYPE_SH7751R=y
-CONFIG_MEMORY_START=0x0c000000
-CONFIG_MEMORY_SIZE=0x00400000
-CONFIG_FLATMEM_MANUAL=y
-CONFIG_SH_7751_SYSTEMH=y
-CONFIG_PREEMPT=y
-# CONFIG_STANDALONE is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=1024
-# CONFIG_INPUT is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_VT is not set
-CONFIG_HW_RANDOM=y
-CONFIG_PROC_KCORE=y
-CONFIG_TMPFS=y
-CONFIG_CRAMFS=y
-CONFIG_ROMFS_FS=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
index 446b3831c2149380265476f47674d4ad4ea72b1e..3d1ae2bfaa6fd7056701e8ddc41538d94a4a1a71 100644 (file)
 /*
  * These will never work in 32-bit, don't even bother.
  */
-#define P1SEGADDR(a)   __futile_remapping_attempt
-#define P2SEGADDR(a)   __futile_remapping_attempt
-#define P3SEGADDR(a)   __futile_remapping_attempt
-#define P4SEGADDR(a)   __futile_remapping_attempt
+#define P1SEGADDR(a)   ({ (void)(a); BUG(); NULL; })
+#define P2SEGADDR(a)   ({ (void)(a); BUG(); NULL; })
+#define P3SEGADDR(a)   ({ (void)(a); BUG(); NULL; })
+#define P4SEGADDR(a)   ({ (void)(a); BUG(); NULL; })
 #endif
 #endif /* P1SEG */
 
index a15f1058bbf439b8895f1b3d277f7e1bcf05c6aa..083ea068e819e80a389d5610bc9e19243d4ed950 100644 (file)
@@ -66,7 +66,6 @@ static inline unsigned long long neff_sign_extend(unsigned long val)
 #define PHYS_ADDR_MASK29               0x1fffffff
 #define PHYS_ADDR_MASK32               0xffffffff
 
-#ifdef CONFIG_PMB
 static inline unsigned long phys_addr_mask(void)
 {
        /* Is the MMU in 29bit mode? */
@@ -75,17 +74,6 @@ static inline unsigned long phys_addr_mask(void)
 
        return PHYS_ADDR_MASK32;
 }
-#elif defined(CONFIG_32BIT)
-static inline unsigned long phys_addr_mask(void)
-{
-       return PHYS_ADDR_MASK32;
-}
-#else
-static inline unsigned long phys_addr_mask(void)
-{
-       return PHYS_ADDR_MASK29;
-}
-#endif
 
 #define PTE_PHYS_MASK          (phys_addr_mask() & PAGE_MASK)
 #define PTE_FLAGS_MASK         (~(PTE_PHYS_MASK) << PAGE_SHIFT)
index 1f1af5afff0374537f989911d4e98f51078a9c1e..10c8b1823a181ef6abd8f07766c801f7c2c6d3f1 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/compiler.h>
 #include <linux/linkage.h>
 #include <asm/types.h>
+#include <asm/uncached.h>
 
 #define AT_VECTOR_SIZE_ARCH 5 /* entries in ARCH_DLINFO */
 
@@ -137,9 +138,6 @@ extern unsigned int instruction_size(unsigned int insn);
 #define instruction_size(insn) (4)
 #endif
 
-extern unsigned long cached_to_uncached;
-extern unsigned long uncached_size;
-
 void per_cpu_trap_init(void);
 void default_idle(void);
 void cpu_idle_wait(void);
index c941b273940581bc4221458a8cabf639829e1500..a4ad1cd9bc4d02740bb8afcb1936a932b2ed3f35 100644 (file)
@@ -145,42 +145,6 @@ do {                                                               \
                __restore_dsp(prev);                            \
 } while (0)
 
-/*
- * Jump to uncached area.
- * When handling TLB or caches, we need to do it from an uncached area.
- */
-#define jump_to_uncached()                     \
-do {                                           \
-       unsigned long __dummy;                  \
-                                               \
-       __asm__ __volatile__(                   \
-               "mova   1f, %0\n\t"             \
-               "add    %1, %0\n\t"             \
-               "jmp    @%0\n\t"                \
-               " nop\n\t"                      \
-               ".balign 4\n"                   \
-               "1:"                            \
-               : "=&z" (__dummy)               \
-               : "r" (cached_to_uncached));    \
-} while (0)
-
-/*
- * Back to cached area.
- */
-#define back_to_cached()                               \
-do {                                                   \
-       unsigned long __dummy;                          \
-       ctrl_barrier();                                 \
-       __asm__ __volatile__(                           \
-               "mov.l  1f, %0\n\t"                     \
-               "jmp    @%0\n\t"                        \
-               " nop\n\t"                              \
-               ".balign 4\n"                           \
-               "1:     .long 2f\n"                     \
-               "2:"                                    \
-               : "=&r" (__dummy));                     \
-} while (0)
-
 #ifdef CONFIG_CPU_HAS_SR_RB
 #define lookup_exception_vector()      \
 ({                                     \
index 36338646dfc81832227e78d39ccf6cdc71df4963..8593bc8d1a4e74af89ace4cb2e767b9fd0567ea6 100644 (file)
@@ -34,9 +34,6 @@ do {                                                          \
                              &next->thread);                   \
 } while (0)
 
-#define jump_to_uncached()     do { } while (0)
-#define back_to_cached()       do { } while (0)
-
 #define __icbi(addr)   __asm__ __volatile__ ( "icbi %0, 0\n\t" : : "r" (addr))
 #define __ocbp(addr)   __asm__ __volatile__ ( "ocbp %0, 0\n\t" : : "r" (addr))
 #define __ocbi(addr)   __asm__ __volatile__ ( "ocbi %0, 0\n\t" : : "r" (addr))
index e3419f96626ad49719130f120bcb71bcbdb40c42..6f8816b79cf152091b1fc08e6cd4dc5d4390bfe2 100644 (file)
@@ -4,15 +4,55 @@
 #include <linux/bug.h>
 
 #ifdef CONFIG_UNCACHED_MAPPING
+extern unsigned long cached_to_uncached;
+extern unsigned long uncached_size;
 extern unsigned long uncached_start, uncached_end;
 
 extern int virt_addr_uncached(unsigned long kaddr);
 extern void uncached_init(void);
 extern void uncached_resize(unsigned long size);
+
+/*
+ * Jump to uncached area.
+ * When handling TLB or caches, we need to do it from an uncached area.
+ */
+#define jump_to_uncached()                     \
+do {                                           \
+       unsigned long __dummy;                  \
+                                               \
+       __asm__ __volatile__(                   \
+               "mova   1f, %0\n\t"             \
+               "add    %1, %0\n\t"             \
+               "jmp    @%0\n\t"                \
+               " nop\n\t"                      \
+               ".balign 4\n"                   \
+               "1:"                            \
+               : "=&z" (__dummy)               \
+               : "r" (cached_to_uncached));    \
+} while (0)
+
+/*
+ * Back to cached area.
+ */
+#define back_to_cached()                               \
+do {                                                   \
+       unsigned long __dummy;                          \
+       ctrl_barrier();                                 \
+       __asm__ __volatile__(                           \
+               "mov.l  1f, %0\n\t"                     \
+               "jmp    @%0\n\t"                        \
+               " nop\n\t"                              \
+               ".balign 4\n"                           \
+               "1:     .long 2f\n"                     \
+               "2:"                                    \
+               : "=&r" (__dummy));                     \
+} while (0)
 #else
 #define virt_addr_uncached(kaddr)      (0)
 #define uncached_init()                        do { } while (0)
 #define uncached_resize(size)          BUG()
+#define jump_to_uncached()             do { } while (0)
+#define back_to_cached()               do { } while (0)
 #endif
 
 #endif /* __ASM_SH_UNCACHED_H */
diff --git a/arch/sh/include/mach-common/mach/edosk7705.h b/arch/sh/include/mach-common/mach/edosk7705.h
deleted file mode 100644 (file)
index efc43b3..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __ASM_SH_EDOSK7705_H
-#define __ASM_SH_EDOSK7705_H
-
-#define __IO_PREFIX sh_edosk7705
-#include <asm/io_generic.h>
-
-#endif /* __ASM_SH_EDOSK7705_H */
index 1aed15856e11ff5bae72b2522f94f816084e0dee..dcb05fa8c164d9c9044df5ce85665953328f7e21 100644 (file)
@@ -68,13 +68,4 @@ extern void microdev_print_fpga_intc_status(void);
 #define __IO_PREFIX microdev
 #include <asm/io_generic.h>
 
-#if defined(CONFIG_PCI)
-unsigned char  microdev_pci_inb(unsigned long port);
-unsigned short microdev_pci_inw(unsigned long port);
-unsigned long  microdev_pci_inl(unsigned long port);
-void           microdev_pci_outb(unsigned char  data, unsigned long port);
-void           microdev_pci_outw(unsigned short data, unsigned long port);
-void           microdev_pci_outl(unsigned long  data, unsigned long port);
-#endif
-
 #endif /* __ASM_SH_MICRODEV_H */
diff --git a/arch/sh/include/mach-common/mach/secureedge5410.h b/arch/sh/include/mach-common/mach/secureedge5410.h
new file mode 100644 (file)
index 0000000..3653b9a
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * include/asm-sh/snapgear.h
+ *
+ * Modified version of io_se.h for the snapgear-specific functions.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License.  See linux/COPYING for more information.
+ *
+ * IO functions for a SnapGear
+ */
+
+#ifndef _ASM_SH_IO_SNAPGEAR_H
+#define _ASM_SH_IO_SNAPGEAR_H
+
+#define __IO_PREFIX    snapgear
+#include <asm/io_generic.h>
+
+/*
+ * We need to remember what was written to the ioport as some bits
+ * are shared with other functions and you cannot read back what was
+ * written :-|
+ *
+ * Bit        Read                   Write
+ * -----------------------------------------------
+ * D0         DCD on ttySC1          power
+ * D1         Reset Switch           heatbeat
+ * D2         ttySC0 CTS (7100)      LAN
+ * D3         -                      WAN
+ * D4         ttySC0 DCD (7100)      CONSOLE
+ * D5         -                      ONLINE
+ * D6         -                      VPN
+ * D7         -                      DTR on ttySC1
+ * D8         -                      ttySC0 RTS (7100)
+ * D9         -                      ttySC0 DTR (7100)
+ * D10        -                      RTC SCLK
+ * D11        RTC DATA               RTC DATA
+ * D12        -                      RTS RESET
+ */
+
+#define SECUREEDGE_IOPORT_ADDR ((volatile short *) 0xb0000000)
+extern unsigned short secureedge5410_ioport;
+
+#define SECUREEDGE_WRITE_IOPORT(val, mask) (*SECUREEDGE_IOPORT_ADDR = \
+        (secureedge5410_ioport = \
+                       ((secureedge5410_ioport & ~(mask)) | ((val) & (mask)))))
+#define SECUREEDGE_READ_IOPORT() \
+        ((*SECUREEDGE_IOPORT_ADDR&0x0817) | (secureedge5410_ioport&~0x0817))
+
+#endif /* _ASM_SH_IO_SNAPGEAR_H */
diff --git a/arch/sh/include/mach-common/mach/snapgear.h b/arch/sh/include/mach-common/mach/snapgear.h
deleted file mode 100644 (file)
index 042d95f..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * include/asm-sh/snapgear.h
- *
- * Modified version of io_se.h for the snapgear-specific functions.
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * IO functions for a SnapGear
- */
-
-#ifndef _ASM_SH_IO_SNAPGEAR_H
-#define _ASM_SH_IO_SNAPGEAR_H
-
-#if defined(CONFIG_CPU_SH4)
-/*
- * The external interrupt lines, these take up ints 0 - 15 inclusive
- * depending on the priority for the interrupt.  In fact the priority
- * is the interrupt :-)
- */
-
-#define IRL0_IRQ       2
-#define IRL0_PRIORITY  13
-
-#define IRL1_IRQ       5
-#define IRL1_PRIORITY  10
-
-#define IRL2_IRQ       8
-#define IRL2_PRIORITY  7
-
-#define IRL3_IRQ       11
-#define IRL3_PRIORITY  4
-#endif
-
-#define __IO_PREFIX    snapgear
-#include <asm/io_generic.h>
-
-#ifdef CONFIG_SH_SECUREEDGE5410
-/*
- * We need to remember what was written to the ioport as some bits
- * are shared with other functions and you cannot read back what was
- * written :-|
- *
- * Bit        Read                   Write
- * -----------------------------------------------
- * D0         DCD on ttySC1          power
- * D1         Reset Switch           heatbeat
- * D2         ttySC0 CTS (7100)      LAN
- * D3         -                      WAN
- * D4         ttySC0 DCD (7100)      CONSOLE
- * D5         -                      ONLINE
- * D6         -                      VPN
- * D7         -                      DTR on ttySC1
- * D8         -                      ttySC0 RTS (7100)
- * D9         -                      ttySC0 DTR (7100)
- * D10        -                      RTC SCLK
- * D11        RTC DATA               RTC DATA
- * D12        -                      RTS RESET
- */
-
-#define SECUREEDGE_IOPORT_ADDR ((volatile short *) 0xb0000000)
-extern unsigned short secureedge5410_ioport;
-
-#define SECUREEDGE_WRITE_IOPORT(val, mask) (*SECUREEDGE_IOPORT_ADDR = \
-        (secureedge5410_ioport = \
-                       ((secureedge5410_ioport & ~(mask)) | ((val) & (mask)))))
-#define SECUREEDGE_READ_IOPORT() \
-        ((*SECUREEDGE_IOPORT_ADDR&0x0817) | (secureedge5410_ioport&~0x0817))
-#endif
-
-#endif /* _ASM_SH_IO_SNAPGEAR_H */
diff --git a/arch/sh/include/mach-common/mach/systemh7751.h b/arch/sh/include/mach-common/mach/systemh7751.h
deleted file mode 100644 (file)
index 4161122..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef __ASM_SH_SYSTEMH_7751SYSTEMH_H
-#define __ASM_SH_SYSTEMH_7751SYSTEMH_H
-
-/*
- * linux/include/asm-sh/systemh/7751systemh.h
- *
- * Copyright (C) 2000  Kazumoto Kojima
- *
- * Hitachi SystemH support
-
- * Modified for 7751 SystemH by
- * Jonathan Short, 2002.
- */
-
-/* Box specific addresses.  */
-
-#define PA_ROM         0x00000000      /* EPROM */
-#define PA_ROM_SIZE    0x00400000      /* EPROM size 4M byte */
-#define PA_FROM                0x01000000      /* EPROM */
-#define PA_FROM_SIZE   0x00400000      /* EPROM size 4M byte */
-#define PA_EXT1                0x04000000
-#define PA_EXT1_SIZE   0x04000000
-#define PA_EXT2                0x08000000
-#define PA_EXT2_SIZE   0x04000000
-#define PA_SDRAM       0x0c000000
-#define PA_SDRAM_SIZE  0x04000000
-
-#define PA_EXT4                0x12000000
-#define PA_EXT4_SIZE   0x02000000
-#define PA_EXT5                0x14000000
-#define PA_EXT5_SIZE   0x04000000
-#define PA_PCIC                0x18000000      /* MR-SHPC-01 PCMCIA */
-
-#define PA_DIPSW0      0xb9000000      /* Dip switch 5,6 */
-#define PA_DIPSW1      0xb9000002      /* Dip switch 7,8 */
-#define PA_LED         0xba000000      /* LED */
-#define        PA_BCR          0xbb000000      /* FPGA on the MS7751SE01 */
-
-#define PA_MRSHPC      0xb83fffe0      /* MR-SHPC-01 PCMCIA controller */
-#define PA_MRSHPC_MW1  0xb8400000      /* MR-SHPC-01 memory window base */
-#define PA_MRSHPC_MW2  0xb8500000      /* MR-SHPC-01 attribute window base */
-#define PA_MRSHPC_IO   0xb8600000      /* MR-SHPC-01 I/O window base */
-#define MRSHPC_MODE     (PA_MRSHPC + 4)
-#define MRSHPC_OPTION   (PA_MRSHPC + 6)
-#define MRSHPC_CSR      (PA_MRSHPC + 8)
-#define MRSHPC_ISR      (PA_MRSHPC + 10)
-#define MRSHPC_ICR      (PA_MRSHPC + 12)
-#define MRSHPC_CPWCR    (PA_MRSHPC + 14)
-#define MRSHPC_MW0CR1   (PA_MRSHPC + 16)
-#define MRSHPC_MW1CR1   (PA_MRSHPC + 18)
-#define MRSHPC_IOWCR1   (PA_MRSHPC + 20)
-#define MRSHPC_MW0CR2   (PA_MRSHPC + 22)
-#define MRSHPC_MW1CR2   (PA_MRSHPC + 24)
-#define MRSHPC_IOWCR2   (PA_MRSHPC + 26)
-#define MRSHPC_CDCR     (PA_MRSHPC + 28)
-#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
-
-#define BCR_ILCRA      (PA_BCR + 0)
-#define BCR_ILCRB      (PA_BCR + 2)
-#define BCR_ILCRC      (PA_BCR + 4)
-#define BCR_ILCRD      (PA_BCR + 6)
-#define BCR_ILCRE      (PA_BCR + 8)
-#define BCR_ILCRF      (PA_BCR + 10)
-#define BCR_ILCRG      (PA_BCR + 12)
-
-#define IRQ_79C973     13
-
-#define __IO_PREFIX    sh7751systemh
-#include <asm/io_generic.h>
-
-#endif  /* __ASM_SH_SYSTEMH_7751SYSTEMH_H */
index 2d9700c6b53a07426bdc6253e55a62effed962c0..0fe2e9329cb25f699acd433dd4f2d9b4b945f00b 100644 (file)
@@ -48,7 +48,7 @@ static struct clk r_clk = {
  * Default rate for the root input clock, reset this with clk_set_rate()
  * from the platform code.
  */
-struct clk extal_clk = {
+static struct clk extal_clk = {
        .rate           = 33333333,
 };
 
@@ -111,7 +111,7 @@ static struct clk div3_clk = {
        .parent         = &pll_clk,
 };
 
-struct clk *main_clks[] = {
+static struct clk *main_clks[] = {
        &r_clk,
        &extal_clk,
        &fll_clk,
@@ -156,7 +156,7 @@ struct clk div4_clks[DIV4_NR] = {
 
 enum { DIV6_V, DIV6_FA, DIV6_FB, DIV6_I, DIV6_S, DIV6_NR };
 
-struct clk div6_clks[DIV6_NR] = {
+static struct clk div6_clks[DIV6_NR] = {
        [DIV6_V] = SH_CLK_DIV6(&div3_clk, VCLKCR, 0),
        [DIV6_FA] = SH_CLK_DIV6(&div3_clk, FCLKACR, 0),
        [DIV6_FB] = SH_CLK_DIV6(&div3_clk, FCLKBCR, 0),
index 09370392aff15d791d612ac57bcdf0c6031d8443..c3e61b36649380f5db818c5f6edb05bfc897de1c 100644 (file)
@@ -79,7 +79,7 @@ config 29BIT
 
 config 32BIT
        bool
-       default y if CPU_SH5
+       default y if CPU_SH5 || !MMU
 
 config PMB
        bool "Support 32-bit physical addressing through PMB"
index 0387932869904a042472cca19b65141b5b8bdc9f..40733a9524021d42d42ddc5a8d7e08ef77a1c155 100644 (file)
@@ -79,21 +79,20 @@ void dma_generic_free_coherent(struct device *dev, size_t size,
 void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
                    enum dma_data_direction direction)
 {
-#if defined(CONFIG_CPU_SH5) || defined(CONFIG_PMB)
-       void *p1addr = vaddr;
-#else
-       void *p1addr = (void*) P1SEGADDR((unsigned long)vaddr);
-#endif
+       void *addr;
+
+       addr = __in_29bit_mode() ?
+              (void *)P1SEGADDR((unsigned long)vaddr) : vaddr;
 
        switch (direction) {
        case DMA_FROM_DEVICE:           /* invalidate only */
-               __flush_invalidate_region(p1addr, size);
+               __flush_invalidate_region(addr, size);
                break;
        case DMA_TO_DEVICE:             /* writeback only */
-               __flush_wback_region(p1addr, size);
+               __flush_wback_region(addr, size);
                break;
        case DMA_BIDIRECTIONAL:         /* writeback and invalidate */
-               __flush_purge_region(p1addr, size);
+               __flush_purge_region(addr, size);
                break;
        default:
                BUG();
index 8a4eca551fc0a08542085faddeac7af373ad091b..a7767da815e91453c5b5526a05f4c72405e4afba 100644 (file)
@@ -28,7 +28,7 @@ EXPORT_SYMBOL(virt_addr_uncached);
 
 void __init uncached_init(void)
 {
-#ifdef CONFIG_29BIT
+#if defined(CONFIG_29BIT) || !defined(CONFIG_MMU)
        uncached_start = P2SEG;
 #else
        uncached_start = memory_end;
index 9f56eb978024ef2b6e93497a6580d00dbc7f62eb..0e68465e7b50920ffcaa8a832402fdfc3670226c 100644 (file)
@@ -26,7 +26,6 @@ HD64461                       HD64461
 7724SE                 SH_7724_SOLUTION_ENGINE
 7751SE                 SH_7751_SOLUTION_ENGINE
 7780SE                 SH_7780_SOLUTION_ENGINE
-7751SYSTEMH            SH_7751_SYSTEMH
 HP6XX                  SH_HP6XX
 DREAMCAST              SH_DREAMCAST
 SNAPGEAR               SH_SECUREEDGE5410
index e0f7ee186721cf554dc142efdfc58350eaf6a7df..b2a6c5de79abf00ddad0354fca8b694937282131 100644 (file)
@@ -23,7 +23,6 @@
 
 #include <linux/interrupt.h>
 #include <linux/threads.h>
-#include <asm/kmap_types.h>
 #include <asm/tlbflush.h>
 #include <asm/homecache.h>
 
index 1480106d1c05c2572177058611ee655db569c41c..3d0f202462609e1401b4737b905cb324332d8b4c 100644 (file)
 #define _ASM_TILE_KMAP_TYPES_H
 
 /*
- * In TILE Linux each set of four of these uses another 16MB chunk of
- * address space, given 64 tiles and 64KB pages, so we only enable
- * ones that are required by the kernel configuration.
+ * In 32-bit TILE Linux we have to balance the desire to have a lot of
+ * nested atomic mappings with the fact that large page sizes and many
+ * processors chew up address space quickly.  In a typical
+ * 64-processor, 64KB-page layout build, making KM_TYPE_NR one larger
+ * adds 4MB of required address-space.  For now we leave KM_TYPE_NR
+ * set to depth 8.
  */
 enum km_type {
+       KM_TYPE_NR = 8
+};
+
+/*
+ * We provide dummy definitions of all the stray values that used to be
+ * required for kmap_atomic() and no longer are.
+ */
+enum {
        KM_BOUNCE_READ,
        KM_SKB_SUNRPC_DATA,
        KM_SKB_DATA_SOFTIRQ,
        KM_USER0,
        KM_USER1,
        KM_BIO_SRC_IRQ,
+       KM_BIO_DST_IRQ,
+       KM_PTE0,
+       KM_PTE1,
        KM_IRQ0,
        KM_IRQ1,
        KM_SOFTIRQ0,
        KM_SOFTIRQ1,
-       KM_MEMCPY0,
-       KM_MEMCPY1,
-#if defined(CONFIG_HIGHPTE)
-       KM_PTE0,
-       KM_PTE1,
-#endif
-       KM_TYPE_NR
+       KM_SYNC_ICACHE,
+       KM_SYNC_DCACHE,
+       KM_UML_USERCOPY,
+       KM_IRQ_PTE,
+       KM_NMI,
+       KM_NMI_PTE,
+       KM_KDB
 };
 
 #endif /* _ASM_TILE_KMAP_TYPES_H */
index dc4ccdd855bca293070ea8bff94a699821d5e01b..a6604e9485da2a188265d618eaaa8a75ec8a4828 100644 (file)
@@ -344,10 +344,8 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
 #if defined(CONFIG_HIGHPTE)
-extern pte_t *_pte_offset_map(pmd_t *, unsigned long address, enum km_type);
-#define pte_offset_map(dir, address) \
-       _pte_offset_map(dir, address, KM_PTE0)
-#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
+extern pte_t *pte_offset_map(pmd_t *, unsigned long address);
+#define pte_unmap(pte) kunmap_atomic(pte)
 #else
 #define pte_offset_map(dir, address) pte_offset_kernel(dir, address)
 #define pte_unmap(pte) do { } while (0)
index 3dc90fa92c704d8fb07d66b034daadd44ee6376b..b16e5db8f0e7225f9e8789a747f9295d341d947d 100644 (file)
@@ -1 +1,4 @@
+#ifdef CONFIG_COMPAT
+#define __ARCH_WANT_STAT64     /* Used for compat_sys_stat64() etc. */
+#endif
 #include <asm-generic/stat.h>
index f2e3ff485333224f022344fad78f7c96b19d5243..b35c2db71199ae3d70fc2b1e29687dc350514a77 100644 (file)
@@ -41,6 +41,7 @@ __SYSCALL(__NR_cmpxchg_badaddr, sys_cmpxchg_badaddr)
 #ifdef CONFIG_COMPAT
 #define __ARCH_WANT_SYS_LLSEEK
 #endif
+#define __ARCH_WANT_SYS_NEWFSTATAT
 #endif
 
 #endif /* _ASM_TILE_UNISTD_H */
index 77739cdd9462dacf2a9188a0a0418c014e6379f9..67617a05e602380a7d1fba86dadba25db17a13ef 100644 (file)
@@ -148,11 +148,11 @@ long tile_compat_sys_msgrcv(int msqid,
 #define compat_sys_readahead sys32_readahead
 #define compat_sys_sync_file_range compat_sys_sync_file_range2
 
-/* The native 64-bit "struct stat" matches the 32-bit "struct stat64". */
-#define compat_sys_stat64 sys_newstat
-#define compat_sys_lstat64 sys_newlstat
-#define compat_sys_fstat64 sys_newfstat
-#define compat_sys_fstatat64 sys_newfstatat
+/* We leverage the "struct stat64" type for 32-bit time_t/nsec. */
+#define compat_sys_stat64 sys_stat64
+#define compat_sys_lstat64 sys_lstat64
+#define compat_sys_fstat64 sys_fstat64
+#define compat_sys_fstatat64 sys_fstatat64
 
 /* The native sys_ptrace dynamically handles compat binaries. */
 #define compat_sys_ptrace sys_ptrace
index 2c54fd43a8a0132533927ed5b5e373940f10ce18..493a0e66d916c618f867034db5647f72acd61999 100644 (file)
@@ -54,7 +54,7 @@ void early_printk(const char *fmt, ...)
 void early_panic(const char *fmt, ...)
 {
        va_list ap;
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        va_start(ap, fmt);
        early_printk("Kernel panic - not syncing: ");
        early_vprintk(fmt, ap);
index 1e54a7843410e57d021dbac9921acf4f39e2f481..e910530436e64a4079ba65e22bdca13e6ad01bfa 100644 (file)
@@ -151,12 +151,12 @@ enum direction_protect {
 
 static void enable_firewall_interrupts(void)
 {
-       raw_local_irq_unmask_now(INT_UDN_FIREWALL);
+       arch_local_irq_unmask_now(INT_UDN_FIREWALL);
 }
 
 static void disable_firewall_interrupts(void)
 {
-       raw_local_irq_mask_now(INT_UDN_FIREWALL);
+       arch_local_irq_mask_now(INT_UDN_FIREWALL);
 }
 
 /* Set up hardwall on this cpu based on the passed hardwall_info. */
@@ -768,13 +768,13 @@ static int hardwall_release(struct inode *inode, struct file *file)
 }
 
 static const struct file_operations dev_hardwall_fops = {
+       .open           = nonseekable_open,
        .unlocked_ioctl = hardwall_ioctl,
 #ifdef CONFIG_COMPAT
        .compat_ioctl   = hardwall_compat_ioctl,
 #endif
        .flush          = hardwall_flush,
        .release        = hardwall_release,
-       .llseek         = noop_llseek,
 };
 
 static struct cdev hardwall_dev;
index e63917687e998907824a62b1783ffef599418818..128805ef8f2c83c1a8b61cf03c5711e5fbb97ff1 100644 (file)
@@ -26,7 +26,7 @@
 #define IS_HW_CLEARED 1
 
 /*
- * The set of interrupts we enable for raw_local_irq_enable().
+ * The set of interrupts we enable for arch_local_irq_enable().
  * This is initialized to have just a single interrupt that the kernel
  * doesn't actually use as a sentinel.  During kernel init,
  * interrupts are added as the kernel gets prepared to support them.
@@ -225,7 +225,7 @@ void __cpuinit setup_irq_regs(void)
        /* Enable interrupt delivery. */
        unmask_irqs(~0UL);
 #if CHIP_HAS_IPI()
-       raw_local_irq_unmask(INT_IPI_K);
+       arch_local_irq_unmask(INT_IPI_K);
 #endif
 }
 
index ba7a265d61796a09168b6c35ed74af23f9fdb256..0d8b9e933487c2847824efc1637364cba8ec84d8 100644 (file)
@@ -182,13 +182,13 @@ static void kexec_find_and_set_command_line(struct kimage *image)
 
                if ((entry & IND_SOURCE)) {
                        void *va =
-                               kmap_atomic_pfn(entry >> PAGE_SHIFT, KM_USER0);
+                               kmap_atomic_pfn(entry >> PAGE_SHIFT);
                        r = kexec_bn2cl(va);
                        if (r) {
                                command_line = r;
                                break;
                        }
-                       kunmap_atomic(va, KM_USER0);
+                       kunmap_atomic(va);
                }
        }
 
@@ -198,7 +198,7 @@ static void kexec_find_and_set_command_line(struct kimage *image)
 
                hverr = hv_set_command_line(
                        (HV_VirtAddr) command_line, strlen(command_line));
-               kunmap_atomic(command_line, KM_USER0);
+               kunmap_atomic(command_line);
        } else {
                pr_info("%s: no command line found; making empty\n",
                       __func__);
index 997e3933f72679718583dae5a82c72c4d2f9fbdb..0858ee6b520f6acf4c23b3a27c8491267919b943 100644 (file)
@@ -34,7 +34,7 @@ void __cpuinit init_messaging(void)
                panic("hv_register_message_state: error %d", rc);
 
        /* Make sure downcall interrupts will be enabled. */
-       raw_local_irq_unmask(INT_INTCTRL_K);
+       arch_local_irq_unmask(INT_INTCTRL_K);
 }
 
 void hv_message_intr(struct pt_regs *regs, int intnum)
index 9cd29884c09f2bfec1cddbacb67579bbd1e821c6..e92e40527d6dcb9855625cafa13a83f08f56df9c 100644 (file)
@@ -50,10 +50,10 @@ long arch_ptrace(struct task_struct *child, long request,
 {
        unsigned long __user *datap = (long __user __force *)data;
        unsigned long tmp;
-       int i;
        long ret = -EIO;
-       unsigned long *childregs;
        char *childreg;
+       struct pt_regs copyregs;
+       int ex1_offset;
 
        switch (request) {
 
@@ -80,6 +80,16 @@ long arch_ptrace(struct task_struct *child, long request,
                if (addr >= PTREGS_SIZE)
                        break;
                childreg = (char *)task_pt_regs(child) + addr;
+
+               /* Guard against overwrites of the privilege level. */
+               ex1_offset = PTREGS_OFFSET_EX1;
+#if defined(CONFIG_COMPAT) && defined(__BIG_ENDIAN)
+               if (is_compat_task())   /* point at low word */
+                       ex1_offset += sizeof(compat_long_t);
+#endif
+               if (addr == ex1_offset)
+                       data = PL_ICS_EX1(USER_PL, EX1_ICS(data));
+
 #ifdef CONFIG_COMPAT
                if (is_compat_task()) {
                        if (addr & (sizeof(compat_long_t)-1))
@@ -96,26 +106,19 @@ long arch_ptrace(struct task_struct *child, long request,
                break;
 
        case PTRACE_GETREGS:  /* Get all registers from the child. */
-               if (!access_ok(VERIFY_WRITE, datap, PTREGS_SIZE))
-                       break;
-               childregs = (long *)task_pt_regs(child);
-               for (i = 0; i < sizeof(struct pt_regs)/sizeof(unsigned long);
-                               ++i) {
-                       ret = __put_user(childregs[i], &datap[i]);
-                       if (ret != 0)
-                               break;
+               if (copy_to_user(datap, task_pt_regs(child),
+                                sizeof(struct pt_regs)) == 0) {
+                       ret = 0;
                }
                break;
 
        case PTRACE_SETREGS:  /* Set all registers in the child. */
-               if (!access_ok(VERIFY_READ, datap, PTREGS_SIZE))
-                       break;
-               childregs = (long *)task_pt_regs(child);
-               for (i = 0; i < sizeof(struct pt_regs)/sizeof(unsigned long);
-                               ++i) {
-                       ret = __get_user(childregs[i], &datap[i]);
-                       if (ret != 0)
-                               break;
+               if (copy_from_user(&copyregs, datap,
+                                  sizeof(struct pt_regs)) == 0) {
+                       copyregs.ex1 =
+                               PL_ICS_EX1(USER_PL, EX1_ICS(copyregs.ex1));
+                       *task_pt_regs(child) = copyregs;
+                       ret = 0;
                }
                break;
 
index acd86d20beba7ab75aed0f484c3b980a836af282..baa3d905fee21c9fc2ef403449f7e4d671ad7e1e 100644 (file)
@@ -27,7 +27,7 @@
 void machine_halt(void)
 {
        warn_early_printk();
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        smp_send_stop();
        hv_halt();
 }
@@ -35,14 +35,14 @@ void machine_halt(void)
 void machine_power_off(void)
 {
        warn_early_printk();
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        smp_send_stop();
        hv_power_off();
 }
 
 void machine_restart(char *cmd)
 {
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        smp_send_stop();
        hv_restart((HV_VirtAddr) "vmlinux", (HV_VirtAddr) cmd);
 }
index ae51cad12da0d6b445666d1796925816b8e7e285..fb0b3cbeae149081a5b3011f0230fbd48f4d56dd 100644 (file)
@@ -868,14 +868,14 @@ void __cpuinit setup_cpu(int boot)
 
        /* Allow asynchronous TLB interrupts. */
 #if CHIP_HAS_TILE_DMA()
-       raw_local_irq_unmask(INT_DMATLB_MISS);
-       raw_local_irq_unmask(INT_DMATLB_ACCESS);
+       arch_local_irq_unmask(INT_DMATLB_MISS);
+       arch_local_irq_unmask(INT_DMATLB_ACCESS);
 #endif
 #if CHIP_HAS_SN_PROC()
-       raw_local_irq_unmask(INT_SNITLB_MISS);
+       arch_local_irq_unmask(INT_SNITLB_MISS);
 #endif
 #ifdef __tilegx__
-       raw_local_irq_unmask(INT_SINGLE_STEP_K);
+       arch_local_irq_unmask(INT_SINGLE_STEP_K);
 #endif
 
        /*
index fb28e85ae3aea3698c7d2cd5da564bb0a5f7fb0d..687719d4abd1eba56fbd591852c8fab51950bc52 100644 (file)
@@ -71,6 +71,9 @@ int restore_sigcontext(struct pt_regs *regs,
        for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i)
                err |= __get_user(regs->regs[i], &sc->gregs[i]);
 
+       /* Ensure that the PL is always set to USER_PL. */
+       regs->ex1 = PL_ICS_EX1(USER_PL, EX1_ICS(regs->ex1));
+
        regs->faultnum = INT_SWINT_1_SIGRETURN;
 
        err |= __get_user(*pr0, &sc->gregs[0]);
@@ -330,7 +333,7 @@ void do_signal(struct pt_regs *regs)
                        current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
                }
 
-               return;
+               goto done;
        }
 
        /* Did we come from a system call? */
@@ -358,4 +361,8 @@ void do_signal(struct pt_regs *regs)
                current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
                sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
        }
+
+done:
+       /* Avoid double syscall restart if there are nested signals. */
+       regs->faultnum = INT_SWINT_1_SIGRETURN;
 }
index 75255d90aff309669b110dff32f2254ede9daa27..9575b37a8b75318d57cd061172d7cd09d0cf8049 100644 (file)
@@ -115,7 +115,7 @@ static void smp_start_cpu_interrupt(void)
 static void smp_stop_cpu_interrupt(void)
 {
        set_cpu_online(smp_processor_id(), 0);
-       raw_local_irq_disable_all();
+       arch_local_irq_disable_all();
        for (;;)
                asm("nap");
 }
index 6bed820e1421ae628c9ad162de3e50eb1f2884bf..f2e156e44692505e620c7e6c1a35e1ca948c3855 100644 (file)
@@ -132,7 +132,7 @@ static int tile_timer_set_next_event(unsigned long ticks,
 {
        BUG_ON(ticks > MAX_TICK);
        __insn_mtspr(SPR_TILE_TIMER_CONTROL, ticks);
-       raw_local_irq_unmask_now(INT_TILE_TIMER);
+       arch_local_irq_unmask_now(INT_TILE_TIMER);
        return 0;
 }
 
@@ -143,7 +143,7 @@ static int tile_timer_set_next_event(unsigned long ticks,
 static void tile_timer_set_mode(enum clock_event_mode mode,
                                struct clock_event_device *evt)
 {
-       raw_local_irq_mask_now(INT_TILE_TIMER);
+       arch_local_irq_mask_now(INT_TILE_TIMER);
 }
 
 /*
@@ -172,7 +172,7 @@ void __cpuinit setup_tile_timer(void)
        evt->cpumask = cpumask_of(smp_processor_id());
 
        /* Start out with timer not firing. */
-       raw_local_irq_mask_now(INT_TILE_TIMER);
+       arch_local_irq_mask_now(INT_TILE_TIMER);
 
        /* Register tile timer. */
        clockevents_register_device(evt);
@@ -188,7 +188,7 @@ void do_timer_interrupt(struct pt_regs *regs, int fault_num)
         * Mask the timer interrupt here, since we are a oneshot timer
         * and there are now by definition no events pending.
         */
-       raw_local_irq_mask(INT_TILE_TIMER);
+       arch_local_irq_mask(INT_TILE_TIMER);
 
        /* Track time spent here in an interrupt context */
        irq_enter();
index dfedea7b266b5d58e6cd445fa8ed0f8ae8fcaea8..f7d4a6ad61e811356ac6bec2b9f235c94f4355c6 100644 (file)
@@ -54,7 +54,7 @@ typedef unsigned long (*memcpy_t)(void *, const void *, unsigned long);
  * we must run with interrupts disabled to avoid the risk of some
  * other code seeing the incoherent data in our cache.  (Recall that
  * our cache is indexed by PA, so even if the other code doesn't use
- * our KM_MEMCPY virtual addresses, they'll still hit in cache using
+ * our kmap_atomic virtual addresses, they'll still hit in cache using
  * the normal VAs that aren't supposed to hit in cache.)
  */
 static void memcpy_multicache(void *dest, const void *source,
@@ -64,6 +64,7 @@ static void memcpy_multicache(void *dest, const void *source,
        unsigned long flags, newsrc, newdst;
        pmd_t *pmdp;
        pte_t *ptep;
+       int type0, type1;
        int cpu = get_cpu();
 
        /*
@@ -77,7 +78,8 @@ static void memcpy_multicache(void *dest, const void *source,
        sim_allow_multiple_caching(1);
 
        /* Set up the new dest mapping */
-       idx = FIX_KMAP_BEGIN + (KM_TYPE_NR * cpu) + KM_MEMCPY0;
+       type0 = kmap_atomic_idx_push();
+       idx = FIX_KMAP_BEGIN + (KM_TYPE_NR * cpu) + type0;
        newdst = __fix_to_virt(idx) + ((unsigned long)dest & (PAGE_SIZE-1));
        pmdp = pmd_offset(pud_offset(pgd_offset_k(newdst), newdst), newdst);
        ptep = pte_offset_kernel(pmdp, newdst);
@@ -87,7 +89,8 @@ static void memcpy_multicache(void *dest, const void *source,
        }
 
        /* Set up the new source mapping */
-       idx += (KM_MEMCPY0 - KM_MEMCPY1);
+       type1 = kmap_atomic_idx_push();
+       idx += (type0 - type1);
        src_pte = hv_pte_set_nc(src_pte);
        src_pte = hv_pte_clear_writable(src_pte);  /* be paranoid */
        newsrc = __fix_to_virt(idx) + ((unsigned long)source & (PAGE_SIZE-1));
@@ -119,6 +122,8 @@ static void memcpy_multicache(void *dest, const void *source,
         * We're done: notify the simulator that all is back to normal,
         * and re-enable interrupts and pre-emption.
         */
+       kmap_atomic_idx_pop();
+       kmap_atomic_idx_pop();
        sim_allow_multiple_caching(0);
        local_irq_restore(flags);
        put_cpu();
index abb57331cf6e1b25fdeccfd295e25ea7464ebbf5..31dbbd9afe47d5cb32590b96e1d7065e2ff5bf24 100644 (file)
@@ -227,7 +227,7 @@ EXPORT_SYMBOL(kmap_atomic_prot);
 void *__kmap_atomic(struct page *page)
 {
        /* PAGE_NONE is a magic value that tells us to check immutability. */
-       return kmap_atomic_prot(page, type, PAGE_NONE);
+       return kmap_atomic_prot(page, PAGE_NONE);
 }
 EXPORT_SYMBOL(__kmap_atomic);
 
index 78e1982cb6c9dc0385e258b81bfc233f23baaaac..0b9ce69b0ee5e755ea6186e1093269507cae156d 100644 (file)
@@ -988,8 +988,12 @@ static long __write_once initfree = 1;
 /* Select whether to free (1) or mark unusable (0) the __init pages. */
 static int __init set_initfree(char *str)
 {
-       strict_strtol(str, 0, &initfree);
-       pr_info("initfree: %s free init pages\n", initfree ? "will" : "won't");
+       long val;
+       if (strict_strtol(str, 0, &val)) {
+               initfree = val;
+               pr_info("initfree: %s free init pages\n",
+                       initfree ? "will" : "won't");
+       }
        return 1;
 }
 __setup("initfree=", set_initfree);
index 335c24621c418b1a7bffdacc2723bbcee665c8e2..1f5430c53d0db4cf62c992c656de7e1b2e9769e6 100644 (file)
@@ -134,9 +134,9 @@ void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
 }
 
 #if defined(CONFIG_HIGHPTE)
-pte_t *_pte_offset_map(pmd_t *dir, unsigned long address, enum km_type type)
+pte_t *_pte_offset_map(pmd_t *dir, unsigned long address)
 {
-       pte_t *pte = kmap_atomic(pmd_page(*dir), type) +
+       pte_t *pte = kmap_atomic(pmd_page(*dir)) +
                (pmd_ptfn(*dir) << HV_LOG2_PAGE_TABLE_ALIGN) & ~PAGE_MASK;
        return &pte[pte_index(address)];
 }
index 908ea5464a518097958083156eb5b0b94f4d021c..fb8b376bf28cb3e04a6bb903900f32838ab02a14 100644 (file)
@@ -720,7 +720,7 @@ static void rmap_remove(struct kvm *kvm, u64 *spte)
        }
 }
 
-static void set_spte_track_bits(u64 *sptep, u64 new_spte)
+static int set_spte_track_bits(u64 *sptep, u64 new_spte)
 {
        pfn_t pfn;
        u64 old_spte = *sptep;
@@ -731,19 +731,20 @@ static void set_spte_track_bits(u64 *sptep, u64 new_spte)
                old_spte = __xchg_spte(sptep, new_spte);
 
        if (!is_rmap_spte(old_spte))
-               return;
+               return 0;
 
        pfn = spte_to_pfn(old_spte);
        if (!shadow_accessed_mask || old_spte & shadow_accessed_mask)
                kvm_set_pfn_accessed(pfn);
        if (!shadow_dirty_mask || (old_spte & shadow_dirty_mask))
                kvm_set_pfn_dirty(pfn);
+       return 1;
 }
 
 static void drop_spte(struct kvm *kvm, u64 *sptep, u64 new_spte)
 {
-       set_spte_track_bits(sptep, new_spte);
-       rmap_remove(kvm, sptep);
+       if (set_spte_track_bits(sptep, new_spte))
+               rmap_remove(kvm, sptep);
 }
 
 static u64 *rmap_next(struct kvm *kvm, unsigned long *rmapp, u64 *spte)
index 2288ad829b327bb68d0efa65c104dcc7f2bbe7b5..cdac9e592aa53ee84b7e184900601ab4730354e5 100644 (file)
@@ -2560,6 +2560,7 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
                !kvm_exception_is_soft(vcpu->arch.exception.nr);
        events->exception.nr = vcpu->arch.exception.nr;
        events->exception.has_error_code = vcpu->arch.exception.has_error_code;
+       events->exception.pad = 0;
        events->exception.error_code = vcpu->arch.exception.error_code;
 
        events->interrupt.injected =
@@ -2573,12 +2574,14 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
        events->nmi.injected = vcpu->arch.nmi_injected;
        events->nmi.pending = vcpu->arch.nmi_pending;
        events->nmi.masked = kvm_x86_ops->get_nmi_mask(vcpu);
+       events->nmi.pad = 0;
 
        events->sipi_vector = vcpu->arch.sipi_vector;
 
        events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING
                         | KVM_VCPUEVENT_VALID_SIPI_VECTOR
                         | KVM_VCPUEVENT_VALID_SHADOW);
+       memset(&events->reserved, 0, sizeof(events->reserved));
 }
 
 static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
@@ -2623,6 +2626,7 @@ static void kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu,
        dbgregs->dr6 = vcpu->arch.dr6;
        dbgregs->dr7 = vcpu->arch.dr7;
        dbgregs->flags = 0;
+       memset(&dbgregs->reserved, 0, sizeof(dbgregs->reserved));
 }
 
 static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
@@ -3106,6 +3110,7 @@ static int kvm_vm_ioctl_get_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
                sizeof(ps->channels));
        ps->flags = kvm->arch.vpit->pit_state.flags;
        mutex_unlock(&kvm->arch.vpit->pit_state.lock);
+       memset(&ps->reserved, 0, sizeof(ps->reserved));
        return r;
 }
 
@@ -3169,10 +3174,6 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
                struct kvm_memslots *slots, *old_slots;
                unsigned long *dirty_bitmap;
 
-               spin_lock(&kvm->mmu_lock);
-               kvm_mmu_slot_remove_write_access(kvm, log->slot);
-               spin_unlock(&kvm->mmu_lock);
-
                r = -ENOMEM;
                dirty_bitmap = vmalloc(n);
                if (!dirty_bitmap)
@@ -3194,6 +3195,10 @@ int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
                dirty_bitmap = old_slots->memslots[log->slot].dirty_bitmap;
                kfree(old_slots);
 
+               spin_lock(&kvm->mmu_lock);
+               kvm_mmu_slot_remove_write_access(kvm, log->slot);
+               spin_unlock(&kvm->mmu_lock);
+
                r = -EFAULT;
                if (copy_to_user(log->dirty_bitmap, dirty_bitmap, n)) {
                        vfree(dirty_bitmap);
@@ -3486,6 +3491,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
                user_ns.clock = kvm->arch.kvmclock_offset + now_ns;
                local_irq_enable();
                user_ns.flags = 0;
+               memset(&user_ns.pad, 0, sizeof(user_ns.pad));
 
                r = -EFAULT;
                if (copy_to_user(argp, &user_ns, sizeof(user_ns)))
@@ -3972,8 +3978,10 @@ int kvm_emulate_wbinvd(struct kvm_vcpu *vcpu)
                return X86EMUL_CONTINUE;
 
        if (kvm_x86_ops->has_wbinvd_exit()) {
+               preempt_disable();
                smp_call_function_many(vcpu->arch.wbinvd_dirty_mask,
                                wbinvd_ipi, NULL, 1);
+               preempt_enable();
                cpumask_clear(vcpu->arch.wbinvd_dirty_mask);
        }
        wbinvd();
index 14cf9077bb2bcf4f01025518b11b0e87e072e9b5..f3ebb30f1b7fd9c7ed93d6328dbe4d8c54b1fd87 100644 (file)
@@ -26,6 +26,7 @@ obj-$(CONFIG_REGULATOR)               += regulator/
 
 # char/ comes before serial/ etc so that the VT console is the boot-time
 # default.
+obj-y                          += tty/
 obj-y                          += char/
 
 # gpu/ comes after char for AGP vs DRM startup
index 767107cce982bfdcb651797eb2fb634dde4f2356..3951020e494ac803001083b186a5b7614eb6d42f 100644 (file)
@@ -4363,9 +4363,9 @@ out_unreg_blkdev:
 out_put_disk:
        while (dr--) {
                del_timer(&motor_off_timer[dr]);
-               put_disk(disks[dr]);
                if (disks[dr]->queue)
                        blk_cleanup_queue(disks[dr]->queue);
+               put_disk(disks[dr]);
        }
        return err;
 }
@@ -4573,8 +4573,8 @@ static void __exit floppy_module_exit(void)
                        device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
                        platform_device_unregister(&floppy_device[drive]);
                }
-               put_disk(disks[drive]);
                blk_cleanup_queue(disks[drive]->queue);
+               put_disk(disks[drive]);
        }
 
        del_timer_sync(&fd_timeout);
diff --git a/drivers/char/.gitignore b/drivers/char/.gitignore
deleted file mode 100644 (file)
index 83683a2..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-consolemap_deftbl.c
-defkeymap.c
index 3a9c01416839ebc785abcdec1405135fce3df817..ba53ec956c95627ff03695a3bbb363f9f5f2f400 100644 (file)
@@ -2,24 +2,10 @@
 # Makefile for the kernel character device drivers.
 #
 
-#
-# This file contains the font map for the default (hardware) font
-#
-FONTMAPFILE = cp437.uni
-
-obj-y   += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o
-
-obj-y                          += tty_mutex.o
-obj-$(CONFIG_LEGACY_PTYS)      += pty.o
-obj-$(CONFIG_UNIX98_PTYS)      += pty.o
+obj-y                          += mem.o random.o
 obj-$(CONFIG_TTY_PRINTK)       += ttyprintk.o
 obj-y                          += misc.o
-obj-$(CONFIG_VT)               += vt_ioctl.o vc_screen.o selection.o keyboard.o
 obj-$(CONFIG_BFIN_JTAG_COMM)   += bfin_jtag_comm.o
-obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o
-obj-$(CONFIG_HW_CONSOLE)       += vt.o defkeymap.o
-obj-$(CONFIG_AUDIT)            += tty_audit.o
-obj-$(CONFIG_MAGIC_SYSRQ)      += sysrq.o
 obj-$(CONFIG_MVME147_SCC)      += generic_serial.o vme_scc.o
 obj-$(CONFIG_MVME162_SCC)      += generic_serial.o vme_scc.o
 obj-$(CONFIG_BVME6000_SCC)     += generic_serial.o vme_scc.o
@@ -41,8 +27,6 @@ obj-$(CONFIG_ISI)             += isicom.o
 obj-$(CONFIG_SYNCLINK)         += synclink.o
 obj-$(CONFIG_SYNCLINKMP)       += synclinkmp.o
 obj-$(CONFIG_SYNCLINK_GT)      += synclink_gt.o
-obj-$(CONFIG_N_HDLC)           += n_hdlc.o
-obj-$(CONFIG_N_GSM)            += n_gsm.o
 obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
 obj-$(CONFIG_SX)               += sx.o generic_serial.o
 obj-$(CONFIG_RIO)              += rio/ generic_serial.o
@@ -74,7 +58,6 @@ obj-$(CONFIG_PRINTER)         += lp.o
 obj-$(CONFIG_APM_EMULATION)    += apm-emulation.o
 
 obj-$(CONFIG_DTLK)             += dtlk.o
-obj-$(CONFIG_R3964)            += n_r3964.o
 obj-$(CONFIG_APPLICOM)         += applicom.o
 obj-$(CONFIG_SONYPI)           += sonypi.o
 obj-$(CONFIG_RTC)              += rtc.o
@@ -115,28 +98,3 @@ obj-$(CONFIG_RAMOOPS)               += ramoops.o
 
 obj-$(CONFIG_JS_RTC)           += js-rtc.o
 js-rtc-y = rtc.o
-
-# Files generated that shall be removed upon make clean
-clean-files := consolemap_deftbl.c defkeymap.c
-
-quiet_cmd_conmk = CONMK   $@
-      cmd_conmk = scripts/conmakehash $< > $@
-
-$(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE)
-       $(call cmd,conmk)
-
-$(obj)/defkeymap.o:  $(obj)/defkeymap.c
-
-# Uncomment if you're changing the keymap and have an appropriate
-# loadkeys version for the map. By default, we'll use the shipped
-# versions.
-# GENERATE_KEYMAP := 1
-
-ifdef GENERATE_KEYMAP
-
-$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map
-       loadkeys --mktable $< > $@.tmp
-       sed -e 's/^static *//' $@.tmp > $@
-       rm $@.tmp
-
-endif
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
deleted file mode 100644 (file)
index 45d3e80..0000000
+++ /dev/null
@@ -1,745 +0,0 @@
-/*
- * consolemap.c
- *
- * Mapping from internal code (such as Latin-1 or Unicode or IBM PC code)
- * to font positions.
- *
- * aeb, 950210
- *
- * Support for multiple unimaps by Jakub Jelinek <jj@ultra.linux.cz>, July 1998
- *
- * Fix bug in inverse translation. Stanislav Voronyi <stas@cnti.uanet.kharkov.ua>, Dec 1998
- */
-
-#include <linux/module.h>
-#include <linux/kd.h>
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <asm/uaccess.h>
-#include <linux/consolemap.h>
-#include <linux/vt_kern.h>
-
-static unsigned short translations[][256] = {
-  /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
-  {
-    0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
-    0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
-    0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
-    0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
-    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
-    0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
-    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
-    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
-    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
-    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
-    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
-    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
-    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
-    0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
-    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
-    0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
-    0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
-    0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
-    0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
-    0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
-    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
-    0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
-    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
-    0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
-    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
-    0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
-    0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
-    0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
-    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
-    0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
-    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
-    0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
-  }, 
-  /* VT100 graphics mapped to Unicode */
-  {
-    0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
-    0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
-    0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
-    0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
-    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
-    0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f,
-    0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
-    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
-    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
-    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
-    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
-    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0,
-    0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
-    0x2591, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
-    0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
-    0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f,
-    0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
-    0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
-    0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
-    0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
-    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
-    0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
-    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
-    0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
-    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
-    0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
-    0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
-    0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
-    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
-    0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
-    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
-    0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
-  },
-  /* IBM Codepage 437 mapped to Unicode */
-  {
-    0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 
-    0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
-    0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
-    0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
-    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
-    0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
-    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
-    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
-    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
-    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
-    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
-    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
-    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
-    0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
-    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
-    0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
-    0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
-    0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
-    0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
-    0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
-    0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
-    0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
-    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
-    0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
-    0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
-    0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
-    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
-    0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
-    0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
-    0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
-    0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
-    0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
-  }, 
-  /* User mapping -- default to codes for direct font mapping */
-  {
-    0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007,
-    0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f,
-    0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017,
-    0xf018, 0xf019, 0xf01a, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
-    0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf025, 0xf026, 0xf027,
-    0xf028, 0xf029, 0xf02a, 0xf02b, 0xf02c, 0xf02d, 0xf02e, 0xf02f,
-    0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
-    0xf038, 0xf039, 0xf03a, 0xf03b, 0xf03c, 0xf03d, 0xf03e, 0xf03f,
-    0xf040, 0xf041, 0xf042, 0xf043, 0xf044, 0xf045, 0xf046, 0xf047,
-    0xf048, 0xf049, 0xf04a, 0xf04b, 0xf04c, 0xf04d, 0xf04e, 0xf04f,
-    0xf050, 0xf051, 0xf052, 0xf053, 0xf054, 0xf055, 0xf056, 0xf057,
-    0xf058, 0xf059, 0xf05a, 0xf05b, 0xf05c, 0xf05d, 0xf05e, 0xf05f,
-    0xf060, 0xf061, 0xf062, 0xf063, 0xf064, 0xf065, 0xf066, 0xf067,
-    0xf068, 0xf069, 0xf06a, 0xf06b, 0xf06c, 0xf06d, 0xf06e, 0xf06f,
-    0xf070, 0xf071, 0xf072, 0xf073, 0xf074, 0xf075, 0xf076, 0xf077,
-    0xf078, 0xf079, 0xf07a, 0xf07b, 0xf07c, 0xf07d, 0xf07e, 0xf07f,
-    0xf080, 0xf081, 0xf082, 0xf083, 0xf084, 0xf085, 0xf086, 0xf087,
-    0xf088, 0xf089, 0xf08a, 0xf08b, 0xf08c, 0xf08d, 0xf08e, 0xf08f,
-    0xf090, 0xf091, 0xf092, 0xf093, 0xf094, 0xf095, 0xf096, 0xf097,
-    0xf098, 0xf099, 0xf09a, 0xf09b, 0xf09c, 0xf09d, 0xf09e, 0xf09f,
-    0xf0a0, 0xf0a1, 0xf0a2, 0xf0a3, 0xf0a4, 0xf0a5, 0xf0a6, 0xf0a7,
-    0xf0a8, 0xf0a9, 0xf0aa, 0xf0ab, 0xf0ac, 0xf0ad, 0xf0ae, 0xf0af,
-    0xf0b0, 0xf0b1, 0xf0b2, 0xf0b3, 0xf0b4, 0xf0b5, 0xf0b6, 0xf0b7,
-    0xf0b8, 0xf0b9, 0xf0ba, 0xf0bb, 0xf0bc, 0xf0bd, 0xf0be, 0xf0bf,
-    0xf0c0, 0xf0c1, 0xf0c2, 0xf0c3, 0xf0c4, 0xf0c5, 0xf0c6, 0xf0c7,
-    0xf0c8, 0xf0c9, 0xf0ca, 0xf0cb, 0xf0cc, 0xf0cd, 0xf0ce, 0xf0cf,
-    0xf0d0, 0xf0d1, 0xf0d2, 0xf0d3, 0xf0d4, 0xf0d5, 0xf0d6, 0xf0d7,
-    0xf0d8, 0xf0d9, 0xf0da, 0xf0db, 0xf0dc, 0xf0dd, 0xf0de, 0xf0df,
-    0xf0e0, 0xf0e1, 0xf0e2, 0xf0e3, 0xf0e4, 0xf0e5, 0xf0e6, 0xf0e7,
-    0xf0e8, 0xf0e9, 0xf0ea, 0xf0eb, 0xf0ec, 0xf0ed, 0xf0ee, 0xf0ef,
-    0xf0f0, 0xf0f1, 0xf0f2, 0xf0f3, 0xf0f4, 0xf0f5, 0xf0f6, 0xf0f7,
-    0xf0f8, 0xf0f9, 0xf0fa, 0xf0fb, 0xf0fc, 0xf0fd, 0xf0fe, 0xf0ff
-  }
-};
-
-/* The standard kernel character-to-font mappings are not invertible
-   -- this is just a best effort. */
-
-#define MAX_GLYPH 512          /* Max possible glyph value */
-
-static int inv_translate[MAX_NR_CONSOLES];
-
-struct uni_pagedir {
-       u16             **uni_pgdir[32];
-       unsigned long   refcount;
-       unsigned long   sum;
-       unsigned char   *inverse_translations[4];
-       u16             *inverse_trans_unicode;
-       int             readonly;
-};
-
-static struct uni_pagedir *dflt;
-
-static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i)
-{
-       int j, glyph;
-       unsigned short *t = translations[i];
-       unsigned char *q;
-       
-       if (!p) return;
-       q = p->inverse_translations[i];
-
-       if (!q) {
-               q = p->inverse_translations[i] = (unsigned char *) 
-                       kmalloc(MAX_GLYPH, GFP_KERNEL);
-               if (!q) return;
-       }
-       memset(q, 0, MAX_GLYPH);
-
-       for (j = 0; j < E_TABSZ; j++) {
-               glyph = conv_uni_to_pc(conp, t[j]);
-               if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) {
-                       /* prefer '-' above SHY etc. */
-                       q[glyph] = j;
-               }
-       }
-}
-
-static void set_inverse_trans_unicode(struct vc_data *conp,
-                                     struct uni_pagedir *p)
-{
-       int i, j, k, glyph;
-       u16 **p1, *p2;
-       u16 *q;
-
-       if (!p) return;
-       q = p->inverse_trans_unicode;
-       if (!q) {
-               q = p->inverse_trans_unicode =
-                       kmalloc(MAX_GLYPH * sizeof(u16), GFP_KERNEL);
-               if (!q)
-                       return;
-       }
-       memset(q, 0, MAX_GLYPH * sizeof(u16));
-
-       for (i = 0; i < 32; i++) {
-               p1 = p->uni_pgdir[i];
-               if (!p1)
-                       continue;
-               for (j = 0; j < 32; j++) {
-                       p2 = p1[j];
-                       if (!p2)
-                               continue;
-                       for (k = 0; k < 64; k++) {
-                               glyph = p2[k];
-                               if (glyph >= 0 && glyph < MAX_GLYPH
-                                              && q[glyph] < 32)
-                                       q[glyph] = (i << 11) + (j << 6) + k;
-                       }
-               }
-       }
-}
-
-unsigned short *set_translate(int m, struct vc_data *vc)
-{
-       inv_translate[vc->vc_num] = m;
-       return translations[m];
-}
-
-/*
- * Inverse translation is impossible for several reasons:
- * 1. The font<->character maps are not 1-1.
- * 2. The text may have been written while a different translation map
- *    was active.
- * Still, it is now possible to a certain extent to cut and paste non-ASCII.
- */
-u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
-{
-       struct uni_pagedir *p;
-       int m;
-       if (glyph < 0 || glyph >= MAX_GLYPH)
-               return 0;
-       else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
-               return glyph;
-       else if (use_unicode) {
-               if (!p->inverse_trans_unicode)
-                       return glyph;
-               else
-                       return p->inverse_trans_unicode[glyph];
-       } else {
-               m = inv_translate[conp->vc_num];
-               if (!p->inverse_translations[m])
-                       return glyph;
-               else
-                       return p->inverse_translations[m][glyph];
-       }
-}
-EXPORT_SYMBOL_GPL(inverse_translate);
-
-static void update_user_maps(void)
-{
-       int i;
-       struct uni_pagedir *p, *q = NULL;
-       
-       for (i = 0; i < MAX_NR_CONSOLES; i++) {
-               if (!vc_cons_allocated(i))
-                       continue;
-               p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
-               if (p && p != q) {
-                       set_inverse_transl(vc_cons[i].d, p, USER_MAP);
-                       set_inverse_trans_unicode(vc_cons[i].d, p);
-                       q = p;
-               }
-       }
-}
-
-/*
- * Load customizable translation table
- * arg points to a 256 byte translation table.
- *
- * The "old" variants are for translation directly to font (using the
- * 0xf000-0xf0ff "transparent" Unicodes) whereas the "new" variants set
- * Unicodes explicitly.
- */
-int con_set_trans_old(unsigned char __user * arg)
-{
-       int i;
-       unsigned short *p = translations[USER_MAP];
-
-       if (!access_ok(VERIFY_READ, arg, E_TABSZ))
-               return -EFAULT;
-
-       for (i=0; i<E_TABSZ ; i++) {
-               unsigned char uc;
-               __get_user(uc, arg+i);
-               p[i] = UNI_DIRECT_BASE | uc;
-       }
-
-       update_user_maps();
-       return 0;
-}
-
-int con_get_trans_old(unsigned char __user * arg)
-{
-       int i, ch;
-       unsigned short *p = translations[USER_MAP];
-
-       if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
-               return -EFAULT;
-
-       for (i=0; i<E_TABSZ ; i++)
-         {
-           ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
-           __put_user((ch & ~0xff) ? 0 : ch, arg+i);
-         }
-       return 0;
-}
-
-int con_set_trans_new(ushort __user * arg)
-{
-       int i;
-       unsigned short *p = translations[USER_MAP];
-
-       if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
-               return -EFAULT;
-
-       for (i=0; i<E_TABSZ ; i++) {
-               unsigned short us;
-               __get_user(us, arg+i);
-               p[i] = us;
-       }
-
-       update_user_maps();
-       return 0;
-}
-
-int con_get_trans_new(ushort __user * arg)
-{
-       int i;
-       unsigned short *p = translations[USER_MAP];
-
-       if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
-               return -EFAULT;
-
-       for (i=0; i<E_TABSZ ; i++)
-         __put_user(p[i], arg+i);
-       
-       return 0;
-}
-
-/*
- * Unicode -> current font conversion 
- *
- * A font has at most 512 chars, usually 256.
- * But one font position may represent several Unicode chars.
- * A hashtable is somewhat of a pain to deal with, so use a
- * "paged table" instead.  Simulation has shown the memory cost of
- * this 3-level paged table scheme to be comparable to a hash table.
- */
-
-extern u8 dfont_unicount[];    /* Defined in console_defmap.c */
-extern u16 dfont_unitable[];
-
-static void con_release_unimap(struct uni_pagedir *p)
-{
-       u16 **p1;
-       int i, j;
-
-       if (p == dflt) dflt = NULL;  
-       for (i = 0; i < 32; i++) {
-               if ((p1 = p->uni_pgdir[i]) != NULL) {
-                       for (j = 0; j < 32; j++)
-                               kfree(p1[j]);
-                       kfree(p1);
-               }
-               p->uni_pgdir[i] = NULL;
-       }
-       for (i = 0; i < 4; i++) {
-               kfree(p->inverse_translations[i]);
-               p->inverse_translations[i] = NULL;
-       }
-       if (p->inverse_trans_unicode) {
-               kfree(p->inverse_trans_unicode);
-               p->inverse_trans_unicode = NULL;
-       }
-}
-
-void con_free_unimap(struct vc_data *vc)
-{
-       struct uni_pagedir *p;
-
-       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-       if (!p)
-               return;
-       *vc->vc_uni_pagedir_loc = 0;
-       if (--p->refcount)
-               return;
-       con_release_unimap(p);
-       kfree(p);
-}
-  
-static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
-{
-       int i, j, k;
-       struct uni_pagedir *q;
-       
-       for (i = 0; i < MAX_NR_CONSOLES; i++) {
-               if (!vc_cons_allocated(i))
-                       continue;
-               q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
-               if (!q || q == p || q->sum != p->sum)
-                       continue;
-               for (j = 0; j < 32; j++) {
-                       u16 **p1, **q1;
-                       p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j];
-                       if (!p1 && !q1)
-                               continue;
-                       if (!p1 || !q1)
-                               break;
-                       for (k = 0; k < 32; k++) {
-                               if (!p1[k] && !q1[k])
-                                       continue;
-                               if (!p1[k] || !q1[k])
-                                       break;
-                               if (memcmp(p1[k], q1[k], 64*sizeof(u16)))
-                                       break;
-                       }
-                       if (k < 32)
-                               break;
-               }
-               if (j == 32) {
-                       q->refcount++;
-                       *conp->vc_uni_pagedir_loc = (unsigned long)q;
-                       con_release_unimap(p);
-                       kfree(p);
-                       return 1;
-               }
-       }
-       return 0;
-}
-
-static int
-con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
-{
-       int i, n;
-       u16 **p1, *p2;
-
-       if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
-               p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
-               if (!p1) return -ENOMEM;
-               for (i = 0; i < 32; i++)
-                       p1[i] = NULL;
-       }
-
-       if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
-               p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
-               if (!p2) return -ENOMEM;
-               memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
-       }
-
-       p2[unicode & 0x3f] = fontpos;
-       
-       p->sum += (fontpos << 20) + unicode;
-
-       return 0;
-}
-
-/* ui is a leftover from using a hashtable, but might be used again */
-int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
-{
-       struct uni_pagedir *p, *q;
-  
-       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-       if (p && p->readonly) return -EIO;
-       if (!p || --p->refcount) {
-               q = kzalloc(sizeof(*p), GFP_KERNEL);
-               if (!q) {
-                       if (p) p->refcount++;
-                       return -ENOMEM;
-               }
-               q->refcount=1;
-               *vc->vc_uni_pagedir_loc = (unsigned long)q;
-       } else {
-               if (p == dflt) dflt = NULL;
-               p->refcount++;
-               p->sum = 0;
-               con_release_unimap(p);
-       }
-       return 0;
-}
-
-int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
-{
-       int err = 0, err1, i;
-       struct uni_pagedir *p, *q;
-
-       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-       if (p->readonly) return -EIO;
-       
-       if (!ct) return 0;
-       
-       if (p->refcount > 1) {
-               int j, k;
-               u16 **p1, *p2, l;
-               
-               err1 = con_clear_unimap(vc, NULL);
-               if (err1) return err1;
-               
-               q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-               for (i = 0, l = 0; i < 32; i++)
-               if ((p1 = p->uni_pgdir[i]))
-                       for (j = 0; j < 32; j++)
-                       if ((p2 = p1[j]))
-                               for (k = 0; k < 64; k++, l++)
-                               if (p2[k] != 0xffff) {
-                                       err1 = con_insert_unipair(q, l, p2[k]);
-                                       if (err1) {
-                                               p->refcount++;
-                                               *vc->vc_uni_pagedir_loc = (unsigned long)p;
-                                               con_release_unimap(q);
-                                               kfree(q);
-                                               return err1; 
-                                       }
-                               }
-               p = q;
-       } else if (p == dflt)
-               dflt = NULL;
-       
-       while (ct--) {
-               unsigned short unicode, fontpos;
-               __get_user(unicode, &list->unicode);
-               __get_user(fontpos, &list->fontpos);
-               if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0)
-                       err = err1;
-               list++;
-       }
-       
-       if (con_unify_unimap(vc, p))
-               return err;
-
-       for (i = 0; i <= 3; i++)
-               set_inverse_transl(vc, p, i); /* Update all inverse translations */
-       set_inverse_trans_unicode(vc, p);
-  
-       return err;
-}
-
-/* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
-   The representation used was the most compact I could come up
-   with.  This routine is executed at sys_setup time, and when the
-   PIO_FONTRESET ioctl is called. */
-
-int con_set_default_unimap(struct vc_data *vc)
-{
-       int i, j, err = 0, err1;
-       u16 *q;
-       struct uni_pagedir *p;
-
-       if (dflt) {
-               p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-               if (p == dflt)
-                       return 0;
-               dflt->refcount++;
-               *vc->vc_uni_pagedir_loc = (unsigned long)dflt;
-               if (p && --p->refcount) {
-                       con_release_unimap(p);
-                       kfree(p);
-               }
-               return 0;
-       }
-       
-       /* The default font is always 256 characters */
-
-       err = con_clear_unimap(vc, NULL);
-       if (err) return err;
-    
-       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-       q = dfont_unitable;
-       
-       for (i = 0; i < 256; i++)
-               for (j = dfont_unicount[i]; j; j--) {
-                       err1 = con_insert_unipair(p, *(q++), i);
-                       if (err1)
-                               err = err1;
-               }
-                       
-       if (con_unify_unimap(vc, p)) {
-               dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-               return err;
-       }
-
-       for (i = 0; i <= 3; i++)
-               set_inverse_transl(vc, p, i);   /* Update all inverse translations */
-       set_inverse_trans_unicode(vc, p);
-       dflt = p;
-       return err;
-}
-EXPORT_SYMBOL(con_set_default_unimap);
-
-int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
-{
-       struct uni_pagedir *q;
-
-       if (!*src_vc->vc_uni_pagedir_loc)
-               return -EINVAL;
-       if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
-               return 0;
-       con_free_unimap(dst_vc);
-       q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
-       q->refcount++;
-       *dst_vc->vc_uni_pagedir_loc = (long)q;
-       return 0;
-}
-
-int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
-{
-       int i, j, k, ect;
-       u16 **p1, *p2;
-       struct uni_pagedir *p;
-
-       ect = 0;
-       if (*vc->vc_uni_pagedir_loc) {
-               p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-               for (i = 0; i < 32; i++)
-               if ((p1 = p->uni_pgdir[i]))
-                       for (j = 0; j < 32; j++)
-                       if ((p2 = *(p1++)))
-                               for (k = 0; k < 64; k++) {
-                                       if (*p2 < MAX_GLYPH && ect++ < ct) {
-                                               __put_user((u_short)((i<<11)+(j<<6)+k),
-                                                          &list->unicode);
-                                               __put_user((u_short) *p2, 
-                                                          &list->fontpos);
-                                               list++;
-                                       }
-                                       p2++;
-                               }
-       }
-       __put_user(ect, uct);
-       return ((ect <= ct) ? 0 : -ENOMEM);
-}
-
-void con_protect_unimap(struct vc_data *vc, int rdonly)
-{
-       struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-       
-       if (p)
-               p->readonly = rdonly;
-}
-
-/*
- * Always use USER_MAP. These functions are used by the keyboard,
- * which shouldn't be affected by G0/G1 switching, etc.
- * If the user map still contains default values, i.e. the
- * direct-to-font mapping, then assume user is using Latin1.
- */
-/* may be called during an interrupt */
-u32 conv_8bit_to_uni(unsigned char c)
-{
-       unsigned short uni = translations[USER_MAP][c];
-       return uni == (0xf000 | c) ? c : uni;
-}
-
-int conv_uni_to_8bit(u32 uni)
-{
-       int c;
-       for (c = 0; c < 0x100; c++)
-               if (translations[USER_MAP][c] == uni ||
-                  (translations[USER_MAP][c] == (c | 0xf000) && uni == c))
-                       return c;
-       return -1;
-}
-
-int
-conv_uni_to_pc(struct vc_data *conp, long ucs) 
-{
-       int h;
-       u16 **p1, *p2;
-       struct uni_pagedir *p;
-  
-       /* Only 16-bit codes supported at this time */
-       if (ucs > 0xffff)
-               return -4;              /* Not found */
-       else if (ucs < 0x20)
-               return -1;              /* Not a printable character */
-       else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f))
-               return -2;                      /* Zero-width space */
-       /*
-        * UNI_DIRECT_BASE indicates the start of the region in the User Zone
-        * which always has a 1:1 mapping to the currently loaded font.  The
-        * UNI_DIRECT_MASK indicates the bit span of the region.
-        */
-       else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
-               return ucs & UNI_DIRECT_MASK;
-  
-       if (!*conp->vc_uni_pagedir_loc)
-               return -3;
-
-       p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;  
-       if ((p1 = p->uni_pgdir[ucs >> 11]) &&
-           (p2 = p1[(ucs >> 6) & 0x1f]) &&
-           (h = p2[ucs & 0x3f]) < MAX_GLYPH)
-               return h;
-
-       return -4;              /* not found */
-}
-
-/*
- * This is called at sys_setup time, after memory and the console are
- * initialized.  It must be possible to call kmalloc(..., GFP_KERNEL)
- * from this function, hence the call from sys_setup.
- */
-void __init 
-console_map_init(void)
-{
-       int i;
-       
-       for (i = 0; i < MAX_NR_CONSOLES; i++)
-               if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
-                       con_set_default_unimap(vc_cons[i].d);
-}
-
-EXPORT_SYMBOL(con_copy_unimap);
diff --git a/drivers/char/cp437.uni b/drivers/char/cp437.uni
deleted file mode 100644 (file)
index bc61634..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-#
-# Unicode table for IBM Codepage 437.  Note that there are many more
-# substitutions that could be conceived (for example, thick-line
-# graphs probably should be replaced with double-line ones, accented
-# Latin characters should replaced with their nonaccented versions,
-# and some upper case Greek characters could be replaced by Latin), however,
-# I have limited myself to the Unicodes used by the kernel ISO 8859-1,
-# DEC VT, and IBM CP 437 tables.
-#
-# --------------------------------
-#
-# Basic IBM dingbats, some of which will never have a purpose clear
-# to mankind
-#
-0x00   U+0000
-0x01   U+263a
-0x02   U+263b
-0x03   U+2665
-0x04   U+2666 U+25c6
-0x05   U+2663
-0x06   U+2660
-0x07   U+2022
-0x08   U+25d8
-0x09   U+25cb
-0x0a   U+25d9
-0x0b   U+2642
-0x0c   U+2640
-0x0d   U+266a
-0x0e   U+266b
-0x0f   U+263c U+00a4
-0x10   U+25b6 U+25ba
-0x11   U+25c0 U+25c4
-0x12   U+2195
-0x13   U+203c
-0x14   U+00b6
-0x15   U+00a7
-0x16   U+25ac
-0x17   U+21a8
-0x18   U+2191
-0x19   U+2193
-0x1a   U+2192
-0x1b   U+2190
-0x1c   U+221f
-0x1d   U+2194
-0x1e   U+25b2
-0x1f   U+25bc
-#
-# The ASCII range is identity-mapped, but some of the characters also
-# have to act as substitutes, especially the upper-case characters.
-#
-0x20   U+0020
-0x21   U+0021
-0x22   U+0022 U+00a8
-0x23   U+0023
-0x24   U+0024
-0x25   U+0025
-0x26   U+0026
-0x27   U+0027 U+00b4
-0x28   U+0028
-0x29   U+0029
-0x2a   U+002a
-0x2b   U+002b
-0x2c   U+002c U+00b8
-0x2d   U+002d U+00ad
-0x2e   U+002e
-0x2f   U+002f
-0x30   U+0030
-0x31   U+0031
-0x32   U+0032
-0x33   U+0033
-0x34   U+0034
-0x35   U+0035
-0x36   U+0036
-0x37   U+0037
-0x38   U+0038
-0x39   U+0039
-0x3a   U+003a
-0x3b   U+003b
-0x3c   U+003c
-0x3d   U+003d
-0x3e   U+003e
-0x3f   U+003f
-0x40   U+0040
-0x41   U+0041 U+00c0 U+00c1 U+00c2 U+00c3
-0x42   U+0042
-0x43   U+0043 U+00a9
-0x44   U+0044 U+00d0
-0x45   U+0045 U+00c8 U+00ca U+00cb
-0x46   U+0046
-0x47   U+0047
-0x48   U+0048
-0x49   U+0049 U+00cc U+00cd U+00ce U+00cf
-0x4a   U+004a
-0x4b   U+004b U+212a
-0x4c   U+004c
-0x4d   U+004d
-0x4e   U+004e
-0x4f   U+004f U+00d2 U+00d3 U+00d4 U+00d5
-0x50   U+0050
-0x51   U+0051
-0x52   U+0052 U+00ae
-0x53   U+0053
-0x54   U+0054
-0x55   U+0055 U+00d9 U+00da U+00db
-0x56   U+0056
-0x57   U+0057
-0x58   U+0058
-0x59   U+0059 U+00dd
-0x5a   U+005a
-0x5b   U+005b
-0x5c   U+005c
-0x5d   U+005d
-0x5e   U+005e
-0x5f   U+005f U+23bd U+f804
-0x60   U+0060
-0x61   U+0061 U+00e3
-0x62   U+0062
-0x63   U+0063
-0x64   U+0064
-0x65   U+0065
-0x66   U+0066
-0x67   U+0067
-0x68   U+0068
-0x69   U+0069
-0x6a   U+006a
-0x6b   U+006b
-0x6c   U+006c
-0x6d   U+006d
-0x6e   U+006e
-0x6f   U+006f U+00f5
-0x70   U+0070
-0x71   U+0071
-0x72   U+0072
-0x73   U+0073
-0x74   U+0074
-0x75   U+0075
-0x76   U+0076
-0x77   U+0077
-0x78   U+0078 U+00d7
-0x79   U+0079 U+00fd
-0x7a   U+007a
-0x7b   U+007b
-0x7c   U+007c U+00a6
-0x7d   U+007d
-0x7e   U+007e
-#
-# Okay, what on Earth is this one supposed to be used for?
-#
-0x7f   U+2302
-#
-# Non-English characters, mostly lower case letters...
-#
-0x80   U+00c7
-0x81   U+00fc
-0x82   U+00e9
-0x83   U+00e2
-0x84   U+00e4
-0x85   U+00e0
-0x86   U+00e5
-0x87   U+00e7
-0x88   U+00ea
-0x89   U+00eb
-0x8a   U+00e8
-0x8b   U+00ef
-0x8c   U+00ee
-0x8d   U+00ec
-0x8e   U+00c4
-0x8f   U+00c5 U+212b
-0x90   U+00c9
-0x91   U+00e6
-0x92   U+00c6
-0x93   U+00f4
-0x94   U+00f6
-0x95   U+00f2
-0x96   U+00fb
-0x97   U+00f9
-0x98   U+00ff
-0x99   U+00d6
-0x9a   U+00dc
-0x9b   U+00a2
-0x9c   U+00a3
-0x9d   U+00a5
-0x9e   U+20a7
-0x9f   U+0192
-0xa0   U+00e1
-0xa1   U+00ed
-0xa2   U+00f3
-0xa3   U+00fa
-0xa4   U+00f1
-0xa5   U+00d1
-0xa6   U+00aa
-0xa7   U+00ba
-0xa8   U+00bf
-0xa9   U+2310
-0xaa   U+00ac
-0xab   U+00bd
-0xac   U+00bc
-0xad   U+00a1
-0xae   U+00ab
-0xaf   U+00bb
-#
-# Block graphics
-#
-0xb0   U+2591
-0xb1   U+2592
-0xb2   U+2593
-0xb3   U+2502
-0xb4   U+2524
-0xb5   U+2561
-0xb6   U+2562
-0xb7   U+2556
-0xb8   U+2555
-0xb9   U+2563
-0xba   U+2551
-0xbb   U+2557
-0xbc   U+255d
-0xbd   U+255c
-0xbe   U+255b
-0xbf   U+2510
-0xc0   U+2514
-0xc1   U+2534
-0xc2   U+252c
-0xc3   U+251c
-0xc4   U+2500
-0xc5   U+253c
-0xc6   U+255e
-0xc7   U+255f
-0xc8   U+255a
-0xc9   U+2554
-0xca   U+2569
-0xcb   U+2566
-0xcc   U+2560
-0xcd   U+2550
-0xce   U+256c
-0xcf   U+2567
-0xd0   U+2568
-0xd1   U+2564
-0xd2   U+2565
-0xd3   U+2559
-0xd4   U+2558
-0xd5   U+2552
-0xd6   U+2553
-0xd7   U+256b
-0xd8   U+256a
-0xd9   U+2518
-0xda   U+250c
-0xdb   U+2588
-0xdc   U+2584
-0xdd   U+258c
-0xde   U+2590
-0xdf   U+2580
-#
-# Greek letters and mathematical symbols
-#
-0xe0   U+03b1
-0xe1   U+03b2 U+00df
-0xe2   U+0393
-0xe3   U+03c0
-0xe4   U+03a3
-0xe5   U+03c3
-0xe6   U+00b5 U+03bc
-0xe7   U+03c4
-0xe8   U+03a6 U+00d8
-0xe9   U+0398
-0xea   U+03a9 U+2126
-0xeb   U+03b4 U+00f0
-0xec   U+221e
-0xed   U+03c6 U+00f8
-0xee   U+03b5 U+2208
-0xef   U+2229
-0xf0   U+2261
-0xf1   U+00b1
-0xf2   U+2265
-0xf3   U+2264
-0xf4   U+2320
-0xf5   U+2321
-0xf6   U+00f7
-0xf7   U+2248
-0xf8   U+00b0
-0xf9   U+2219
-0xfa   U+00b7
-0xfb   U+221a
-0xfc   U+207f
-0xfd   U+00b2
-#
-# Square bullet, non-spacing blank
-# Mapping U+fffd to the square bullet means it is the substitution
-# character
-# 
-0xfe   U+25a0 U+fffd
-0xff   U+00a0
diff --git a/drivers/char/defkeymap.c_shipped b/drivers/char/defkeymap.c_shipped
deleted file mode 100644 (file)
index d2208df..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-/* Do not edit this file! It was automatically generated by   */
-/*    loadkeys --mktable defkeymap.map > defkeymap.c          */
-
-#include <linux/types.h>
-#include <linux/keyboard.h>
-#include <linux/kd.h>
-
-u_short plain_map[NR_KEYS] = {
-       0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
-       0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf07f, 0xf009,
-       0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
-       0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73,
-       0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
-       0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76,
-       0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf30c,
-       0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
-       0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf209, 0xf307,
-       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
-       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03c, 0xf10a,
-       0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-u_short shift_map[NR_KEYS] = {
-       0xf200, 0xf01b, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e,
-       0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07f, 0xf009,
-       0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49,
-       0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf201, 0xf702, 0xfb41, 0xfb53,
-       0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a,
-       0xf022, 0xf07e, 0xf700, 0xf07c, 0xfb5a, 0xfb58, 0xfb43, 0xfb56,
-       0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf700, 0xf30c,
-       0xf703, 0xf020, 0xf207, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e,
-       0xf10f, 0xf110, 0xf111, 0xf112, 0xf113, 0xf213, 0xf203, 0xf307,
-       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
-       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03e, 0xf10a,
-       0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf20b, 0xf601, 0xf602, 0xf117, 0xf600, 0xf20a, 0xf115, 0xf116,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-u_short altgr_map[NR_KEYS] = {
-       0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
-       0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200,
-       0xfb71, 0xfb77, 0xf918, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
-       0xfb6f, 0xfb70, 0xf200, 0xf07e, 0xf201, 0xf702, 0xf914, 0xfb73,
-       0xf917, 0xf919, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf200,
-       0xf200, 0xf200, 0xf700, 0xf200, 0xfb7a, 0xfb78, 0xf916, 0xfb76,
-       0xf915, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
-       0xf703, 0xf200, 0xf207, 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510,
-       0xf511, 0xf512, 0xf513, 0xf514, 0xf515, 0xf208, 0xf202, 0xf911,
-       0xf912, 0xf913, 0xf30b, 0xf90e, 0xf90f, 0xf910, 0xf30a, 0xf90b,
-       0xf90c, 0xf90d, 0xf90a, 0xf310, 0xf206, 0xf200, 0xf07c, 0xf516,
-       0xf517, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-u_short ctrl_map[NR_KEYS] = {
-       0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e,
-       0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200,
-       0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
-       0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013,
-       0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
-       0xf007, 0xf000, 0xf700, 0xf01c, 0xf01a, 0xf018, 0xf003, 0xf016,
-       0xf002, 0xf00e, 0xf00d, 0xf200, 0xf20e, 0xf07f, 0xf700, 0xf30c,
-       0xf703, 0xf000, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
-       0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf204, 0xf307,
-       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
-       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf10a,
-       0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-u_short shift_ctrl_map[NR_KEYS] = {
-       0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200,
-       0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
-       0xf00f, 0xf010, 0xf200, 0xf200, 0xf201, 0xf702, 0xf001, 0xf013,
-       0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
-       0xf200, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016,
-       0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
-       0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf208, 0xf200, 0xf307,
-       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
-       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-u_short alt_map[NR_KEYS] = {
-       0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836,
-       0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf87f, 0xf809,
-       0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869,
-       0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf80d, 0xf702, 0xf861, 0xf873,
-       0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b,
-       0xf827, 0xf860, 0xf700, 0xf85c, 0xf87a, 0xf878, 0xf863, 0xf876,
-       0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf700, 0xf30c,
-       0xf703, 0xf820, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504,
-       0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf209, 0xf907,
-       0xf908, 0xf909, 0xf30b, 0xf904, 0xf905, 0xf906, 0xf30a, 0xf901,
-       0xf902, 0xf903, 0xf900, 0xf310, 0xf206, 0xf200, 0xf83c, 0xf50a,
-       0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf118, 0xf210, 0xf211, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-u_short ctrl_alt_map[NR_KEYS] = {
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809,
-       0xf80f, 0xf810, 0xf200, 0xf200, 0xf201, 0xf702, 0xf801, 0xf813,
-       0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200,
-       0xf200, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816,
-       0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
-       0xf703, 0xf200, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504,
-       0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf200, 0xf307,
-       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
-       0xf302, 0xf303, 0xf300, 0xf20c, 0xf206, 0xf200, 0xf200, 0xf50a,
-       0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
-       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf20c,
-       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
-       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-};
-
-ushort *key_maps[MAX_NR_KEYMAPS] = {
-       plain_map, shift_map, altgr_map, NULL,
-       ctrl_map, shift_ctrl_map, NULL, NULL,
-       alt_map, NULL, NULL, NULL,
-       ctrl_alt_map, NULL
-};
-
-unsigned int keymap_count = 7;
-
-/*
- * Philosophy: most people do not define more strings, but they who do
- * often want quite a lot of string space. So, we statically allocate
- * the default and allocate dynamically in chunks of 512 bytes.
- */
-
-char func_buf[] = {
-       '\033', '[', '[', 'A', 0, 
-       '\033', '[', '[', 'B', 0, 
-       '\033', '[', '[', 'C', 0, 
-       '\033', '[', '[', 'D', 0, 
-       '\033', '[', '[', 'E', 0, 
-       '\033', '[', '1', '7', '~', 0, 
-       '\033', '[', '1', '8', '~', 0, 
-       '\033', '[', '1', '9', '~', 0, 
-       '\033', '[', '2', '0', '~', 0, 
-       '\033', '[', '2', '1', '~', 0, 
-       '\033', '[', '2', '3', '~', 0, 
-       '\033', '[', '2', '4', '~', 0, 
-       '\033', '[', '2', '5', '~', 0, 
-       '\033', '[', '2', '6', '~', 0, 
-       '\033', '[', '2', '8', '~', 0, 
-       '\033', '[', '2', '9', '~', 0, 
-       '\033', '[', '3', '1', '~', 0, 
-       '\033', '[', '3', '2', '~', 0, 
-       '\033', '[', '3', '3', '~', 0, 
-       '\033', '[', '3', '4', '~', 0, 
-       '\033', '[', '1', '~', 0, 
-       '\033', '[', '2', '~', 0, 
-       '\033', '[', '3', '~', 0, 
-       '\033', '[', '4', '~', 0, 
-       '\033', '[', '5', '~', 0, 
-       '\033', '[', '6', '~', 0, 
-       '\033', '[', 'M', 0, 
-       '\033', '[', 'P', 0, 
-};
-
-char *funcbufptr = func_buf;
-int funcbufsize = sizeof(func_buf);
-int funcbufleft = 0;          /* space left */
-
-char *func_table[MAX_NR_FUNC] = {
-       func_buf + 0,
-       func_buf + 5,
-       func_buf + 10,
-       func_buf + 15,
-       func_buf + 20,
-       func_buf + 25,
-       func_buf + 31,
-       func_buf + 37,
-       func_buf + 43,
-       func_buf + 49,
-       func_buf + 55,
-       func_buf + 61,
-       func_buf + 67,
-       func_buf + 73,
-       func_buf + 79,
-       func_buf + 85,
-       func_buf + 91,
-       func_buf + 97,
-       func_buf + 103,
-       func_buf + 109,
-       func_buf + 115,
-       func_buf + 120,
-       func_buf + 125,
-       func_buf + 130,
-       func_buf + 135,
-       func_buf + 140,
-       func_buf + 145,
-       NULL,
-       NULL,
-       func_buf + 149,
-       NULL,
-};
-
-struct kbdiacruc accent_table[MAX_DIACR] = {
-       {'`', 'A', 0300},       {'`', 'a', 0340},
-       {'\'', 'A', 0301},      {'\'', 'a', 0341},
-       {'^', 'A', 0302},       {'^', 'a', 0342},
-       {'~', 'A', 0303},       {'~', 'a', 0343},
-       {'"', 'A', 0304},       {'"', 'a', 0344},
-       {'O', 'A', 0305},       {'o', 'a', 0345},
-       {'0', 'A', 0305},       {'0', 'a', 0345},
-       {'A', 'A', 0305},       {'a', 'a', 0345},
-       {'A', 'E', 0306},       {'a', 'e', 0346},
-       {',', 'C', 0307},       {',', 'c', 0347},
-       {'`', 'E', 0310},       {'`', 'e', 0350},
-       {'\'', 'E', 0311},      {'\'', 'e', 0351},
-       {'^', 'E', 0312},       {'^', 'e', 0352},
-       {'"', 'E', 0313},       {'"', 'e', 0353},
-       {'`', 'I', 0314},       {'`', 'i', 0354},
-       {'\'', 'I', 0315},      {'\'', 'i', 0355},
-       {'^', 'I', 0316},       {'^', 'i', 0356},
-       {'"', 'I', 0317},       {'"', 'i', 0357},
-       {'-', 'D', 0320},       {'-', 'd', 0360},
-       {'~', 'N', 0321},       {'~', 'n', 0361},
-       {'`', 'O', 0322},       {'`', 'o', 0362},
-       {'\'', 'O', 0323},      {'\'', 'o', 0363},
-       {'^', 'O', 0324},       {'^', 'o', 0364},
-       {'~', 'O', 0325},       {'~', 'o', 0365},
-       {'"', 'O', 0326},       {'"', 'o', 0366},
-       {'/', 'O', 0330},       {'/', 'o', 0370},
-       {'`', 'U', 0331},       {'`', 'u', 0371},
-       {'\'', 'U', 0332},      {'\'', 'u', 0372},
-       {'^', 'U', 0333},       {'^', 'u', 0373},
-       {'"', 'U', 0334},       {'"', 'u', 0374},
-       {'\'', 'Y', 0335},      {'\'', 'y', 0375},
-       {'T', 'H', 0336},       {'t', 'h', 0376},
-       {'s', 's', 0337},       {'"', 'y', 0377},
-       {'s', 'z', 0337},       {'i', 'j', 0377},
-};
-
-unsigned int accent_table_size = 68;
diff --git a/drivers/char/defkeymap.map b/drivers/char/defkeymap.map
deleted file mode 100644 (file)
index 50b30ca..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-# Default kernel keymap. This uses 7 modifier combinations.
-keymaps 0-2,4-5,8,12
-# Change the above line into
-#      keymaps 0-2,4-6,8,12
-# in case you want the entries
-#      altgr   control keycode  83 = Boot            
-#      altgr   control keycode 111 = Boot            
-# below.
-#
-# In fact AltGr is used very little, and one more keymap can
-# be saved by mapping AltGr to Alt (and adapting a few entries):
-# keycode 100 = Alt
-#
-keycode   1 = Escape           Escape          
-       alt     keycode   1 = Meta_Escape     
-keycode   2 = one              exclam          
-       alt     keycode   2 = Meta_one        
-keycode   3 = two              at               at              
-       control keycode   3 = nul             
-       shift   control keycode   3 = nul             
-       alt     keycode   3 = Meta_two        
-keycode   4 = three            numbersign      
-       control keycode   4 = Escape          
-       alt     keycode   4 = Meta_three      
-keycode   5 = four             dollar           dollar          
-       control keycode   5 = Control_backslash
-       alt     keycode   5 = Meta_four       
-keycode   6 = five             percent         
-       control keycode   6 = Control_bracketright
-       alt     keycode   6 = Meta_five       
-keycode   7 = six              asciicircum     
-       control keycode   7 = Control_asciicircum
-       alt     keycode   7 = Meta_six        
-keycode   8 = seven            ampersand        braceleft       
-       control keycode   8 = Control_underscore
-       alt     keycode   8 = Meta_seven      
-keycode   9 = eight            asterisk         bracketleft     
-       control keycode   9 = Delete          
-       alt     keycode   9 = Meta_eight      
-keycode  10 = nine             parenleft        bracketright    
-       alt     keycode  10 = Meta_nine       
-keycode  11 = zero             parenright       braceright      
-       alt     keycode  11 = Meta_zero       
-keycode  12 = minus            underscore       backslash       
-       control keycode  12 = Control_underscore
-       shift   control keycode  12 = Control_underscore
-       alt     keycode  12 = Meta_minus      
-keycode  13 = equal            plus            
-       alt     keycode  13 = Meta_equal      
-keycode  14 = Delete           Delete          
-       control keycode  14 = BackSpace
-       alt     keycode  14 = Meta_Delete     
-keycode  15 = Tab              Tab             
-       alt     keycode  15 = Meta_Tab        
-keycode  16 = q               
-keycode  17 = w               
-keycode  18 = e
-       altgr   keycode  18 = Hex_E   
-keycode  19 = r               
-keycode  20 = t               
-keycode  21 = y               
-keycode  22 = u               
-keycode  23 = i               
-keycode  24 = o               
-keycode  25 = p               
-keycode  26 = bracketleft      braceleft       
-       control keycode  26 = Escape          
-       alt     keycode  26 = Meta_bracketleft
-keycode  27 = bracketright     braceright       asciitilde      
-       control keycode  27 = Control_bracketright
-       alt     keycode  27 = Meta_bracketright
-keycode  28 = Return          
-       alt     keycode  28 = Meta_Control_m  
-keycode  29 = Control         
-keycode  30 = a
-       altgr   keycode  30 = Hex_A
-keycode  31 = s               
-keycode  32 = d
-       altgr   keycode  32 = Hex_D   
-keycode  33 = f
-       altgr   keycode  33 = Hex_F               
-keycode  34 = g               
-keycode  35 = h               
-keycode  36 = j               
-keycode  37 = k               
-keycode  38 = l               
-keycode  39 = semicolon        colon           
-       alt     keycode  39 = Meta_semicolon  
-keycode  40 = apostrophe       quotedbl        
-       control keycode  40 = Control_g       
-       alt     keycode  40 = Meta_apostrophe 
-keycode  41 = grave            asciitilde      
-       control keycode  41 = nul             
-       alt     keycode  41 = Meta_grave      
-keycode  42 = Shift           
-keycode  43 = backslash        bar             
-       control keycode  43 = Control_backslash
-       alt     keycode  43 = Meta_backslash  
-keycode  44 = z               
-keycode  45 = x               
-keycode  46 = c
-       altgr   keycode  46 = Hex_C   
-keycode  47 = v               
-keycode  48 = b
-       altgr   keycode  48 = Hex_B
-keycode  49 = n               
-keycode  50 = m               
-keycode  51 = comma            less            
-       alt     keycode  51 = Meta_comma      
-keycode  52 = period           greater         
-       control keycode  52 = Compose         
-       alt     keycode  52 = Meta_period     
-keycode  53 = slash            question        
-       control keycode  53 = Delete          
-       alt     keycode  53 = Meta_slash      
-keycode  54 = Shift           
-keycode  55 = KP_Multiply     
-keycode  56 = Alt             
-keycode  57 = space            space           
-       control keycode  57 = nul             
-       alt     keycode  57 = Meta_space      
-keycode  58 = Caps_Lock       
-keycode  59 = F1               F11              Console_13      
-       control keycode  59 = F1              
-       alt     keycode  59 = Console_1       
-       control alt     keycode  59 = Console_1       
-keycode  60 = F2               F12              Console_14      
-       control keycode  60 = F2              
-       alt     keycode  60 = Console_2       
-       control alt     keycode  60 = Console_2       
-keycode  61 = F3               F13              Console_15      
-       control keycode  61 = F3              
-       alt     keycode  61 = Console_3       
-       control alt     keycode  61 = Console_3       
-keycode  62 = F4               F14              Console_16      
-       control keycode  62 = F4              
-       alt     keycode  62 = Console_4       
-       control alt     keycode  62 = Console_4       
-keycode  63 = F5               F15              Console_17      
-       control keycode  63 = F5              
-       alt     keycode  63 = Console_5       
-       control alt     keycode  63 = Console_5       
-keycode  64 = F6               F16              Console_18      
-       control keycode  64 = F6              
-       alt     keycode  64 = Console_6       
-       control alt     keycode  64 = Console_6       
-keycode  65 = F7               F17              Console_19      
-       control keycode  65 = F7              
-       alt     keycode  65 = Console_7       
-       control alt     keycode  65 = Console_7       
-keycode  66 = F8               F18              Console_20      
-       control keycode  66 = F8              
-       alt     keycode  66 = Console_8       
-       control alt     keycode  66 = Console_8       
-keycode  67 = F9               F19              Console_21      
-       control keycode  67 = F9              
-       alt     keycode  67 = Console_9       
-       control alt     keycode  67 = Console_9       
-keycode  68 = F10              F20              Console_22      
-       control keycode  68 = F10             
-       alt     keycode  68 = Console_10      
-       control alt     keycode  68 = Console_10      
-keycode  69 = Num_Lock
-       shift   keycode  69 = Bare_Num_Lock
-keycode  70 = Scroll_Lock      Show_Memory      Show_Registers  
-       control keycode  70 = Show_State      
-       alt     keycode  70 = Scroll_Lock     
-keycode  71 = KP_7            
-       alt     keycode  71 = Ascii_7         
-       altgr   keycode  71 = Hex_7         
-keycode  72 = KP_8            
-       alt     keycode  72 = Ascii_8         
-       altgr   keycode  72 = Hex_8         
-keycode  73 = KP_9            
-       alt     keycode  73 = Ascii_9         
-       altgr   keycode  73 = Hex_9         
-keycode  74 = KP_Subtract     
-keycode  75 = KP_4            
-       alt     keycode  75 = Ascii_4         
-       altgr   keycode  75 = Hex_4         
-keycode  76 = KP_5            
-       alt     keycode  76 = Ascii_5         
-       altgr   keycode  76 = Hex_5         
-keycode  77 = KP_6            
-       alt     keycode  77 = Ascii_6         
-       altgr   keycode  77 = Hex_6         
-keycode  78 = KP_Add          
-keycode  79 = KP_1            
-       alt     keycode  79 = Ascii_1         
-       altgr   keycode  79 = Hex_1         
-keycode  80 = KP_2            
-       alt     keycode  80 = Ascii_2         
-       altgr   keycode  80 = Hex_2         
-keycode  81 = KP_3            
-       alt     keycode  81 = Ascii_3         
-       altgr   keycode  81 = Hex_3         
-keycode  82 = KP_0            
-       alt     keycode  82 = Ascii_0         
-       altgr   keycode  82 = Hex_0         
-keycode  83 = KP_Period       
-#      altgr   control keycode  83 = Boot            
-       control alt     keycode  83 = Boot            
-keycode  84 = Last_Console    
-keycode  85 =
-keycode  86 = less             greater          bar             
-       alt     keycode  86 = Meta_less       
-keycode  87 = F11              F11              Console_23      
-       control keycode  87 = F11             
-       alt     keycode  87 = Console_11      
-       control alt     keycode  87 = Console_11      
-keycode  88 = F12              F12              Console_24      
-       control keycode  88 = F12             
-       alt     keycode  88 = Console_12      
-       control alt     keycode  88 = Console_12      
-keycode  89 =
-keycode  90 =
-keycode  91 =
-keycode  92 =
-keycode  93 =
-keycode  94 =
-keycode  95 =
-keycode  96 = KP_Enter        
-keycode  97 = Control         
-keycode  98 = KP_Divide       
-keycode  99 = Control_backslash
-       control keycode  99 = Control_backslash
-       alt     keycode  99 = Control_backslash
-keycode 100 = AltGr           
-keycode 101 = Break           
-keycode 102 = Find            
-keycode 103 = Up              
-keycode 104 = Prior           
-       shift   keycode 104 = Scroll_Backward 
-keycode 105 = Left            
-       alt     keycode 105 = Decr_Console
-keycode 106 = Right           
-       alt     keycode 106 = Incr_Console
-keycode 107 = Select          
-keycode 108 = Down            
-keycode 109 = Next            
-       shift   keycode 109 = Scroll_Forward  
-keycode 110 = Insert          
-keycode 111 = Remove          
-#      altgr   control keycode 111 = Boot            
-       control alt     keycode 111 = Boot            
-keycode 112 = Macro           
-keycode 113 = F13             
-keycode 114 = F14             
-keycode 115 = Help            
-keycode 116 = Do              
-keycode 117 = F17             
-keycode 118 = KP_MinPlus      
-keycode 119 = Pause           
-keycode 120 =
-keycode 121 =
-keycode 122 =
-keycode 123 =
-keycode 124 =
-keycode 125 =
-keycode 126 =
-keycode 127 =
-string F1 = "\033[[A"
-string F2 = "\033[[B"
-string F3 = "\033[[C"
-string F4 = "\033[[D"
-string F5 = "\033[[E"
-string F6 = "\033[17~"
-string F7 = "\033[18~"
-string F8 = "\033[19~"
-string F9 = "\033[20~"
-string F10 = "\033[21~"
-string F11 = "\033[23~"
-string F12 = "\033[24~"
-string F13 = "\033[25~"
-string F14 = "\033[26~"
-string F15 = "\033[28~"
-string F16 = "\033[29~"
-string F17 = "\033[31~"
-string F18 = "\033[32~"
-string F19 = "\033[33~"
-string F20 = "\033[34~"
-string Find = "\033[1~"
-string Insert = "\033[2~"
-string Remove = "\033[3~"
-string Select = "\033[4~"
-string Prior = "\033[5~"
-string Next = "\033[6~"
-string Macro = "\033[M"
-string Pause = "\033[P"
-compose '`' 'A' to 'À'
-compose '`' 'a' to 'à'
-compose '\'' 'A' to 'Á'
-compose '\'' 'a' to 'á'
-compose '^' 'A' to 'Â'
-compose '^' 'a' to 'â'
-compose '~' 'A' to 'Ã'
-compose '~' 'a' to 'ã'
-compose '"' 'A' to 'Ä'
-compose '"' 'a' to 'ä'
-compose 'O' 'A' to 'Å'
-compose 'o' 'a' to 'å'
-compose '0' 'A' to 'Å'
-compose '0' 'a' to 'å'
-compose 'A' 'A' to 'Å'
-compose 'a' 'a' to 'å'
-compose 'A' 'E' to 'Æ'
-compose 'a' 'e' to 'æ'
-compose ',' 'C' to 'Ç'
-compose ',' 'c' to 'ç'
-compose '`' 'E' to 'È'
-compose '`' 'e' to 'è'
-compose '\'' 'E' to 'É'
-compose '\'' 'e' to 'é'
-compose '^' 'E' to 'Ê'
-compose '^' 'e' to 'ê'
-compose '"' 'E' to 'Ë'
-compose '"' 'e' to 'ë'
-compose '`' 'I' to 'Ì'
-compose '`' 'i' to 'ì'
-compose '\'' 'I' to 'Í'
-compose '\'' 'i' to 'í'
-compose '^' 'I' to 'Î'
-compose '^' 'i' to 'î'
-compose '"' 'I' to 'Ï'
-compose '"' 'i' to 'ï'
-compose '-' 'D' to 'Ð'
-compose '-' 'd' to 'ð'
-compose '~' 'N' to 'Ñ'
-compose '~' 'n' to 'ñ'
-compose '`' 'O' to 'Ò'
-compose '`' 'o' to 'ò'
-compose '\'' 'O' to 'Ó'
-compose '\'' 'o' to 'ó'
-compose '^' 'O' to 'Ô'
-compose '^' 'o' to 'ô'
-compose '~' 'O' to 'Õ'
-compose '~' 'o' to 'õ'
-compose '"' 'O' to 'Ö'
-compose '"' 'o' to 'ö'
-compose '/' 'O' to 'Ø'
-compose '/' 'o' to 'ø'
-compose '`' 'U' to 'Ù'
-compose '`' 'u' to 'ù'
-compose '\'' 'U' to 'Ú'
-compose '\'' 'u' to 'ú'
-compose '^' 'U' to 'Û'
-compose '^' 'u' to 'û'
-compose '"' 'U' to 'Ü'
-compose '"' 'u' to 'ü'
-compose '\'' 'Y' to 'Ý'
-compose '\'' 'y' to 'ý'
-compose 'T' 'H' to 'Þ'
-compose 't' 'h' to 'þ'
-compose 's' 's' to 'ß'
-compose '"' 'y' to 'ÿ'
-compose 's' 'z' to 'ß'
-compose 'i' 'j' to 'ÿ'
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
deleted file mode 100644 (file)
index e95d787..0000000
+++ /dev/null
@@ -1,1454 +0,0 @@
-/*
- * linux/drivers/char/keyboard.c
- *
- * Written for linux by Johan Myreen as a translation from
- * the assembly version by Linus (with diacriticals added)
- *
- * Some additional features added by Christoph Niemann (ChN), March 1993
- *
- * Loadable keymaps by Risto Kankkunen, May 1993
- *
- * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
- * Added decr/incr_console, dynamic keymaps, Unicode support,
- * dynamic function/string keys, led setting,  Sept 1994
- * `Sticky' modifier keys, 951006.
- *
- * 11-11-96: SAK should now work in the raw mode (Martin Mares)
- *
- * Modified to provide 'generic' keyboard support by Hamish Macdonald
- * Merge with the m68k keyboard driver and split-off of the PC low-level
- * parts by Geert Uytterhoeven, May 1997
- *
- * 27-05-97: Added support for the Magic SysRq Key (Martin Mares)
- * 30-07-98: Dead keys redone, aeb@cwi.nl.
- * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik)
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/consolemap.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/irq.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/kbd_diacr.h>
-#include <linux/vt_kern.h>
-#include <linux/input.h>
-#include <linux/reboot.h>
-#include <linux/notifier.h>
-#include <linux/jiffies.h>
-
-extern void ctrl_alt_del(void);
-
-/*
- * Exported functions/variables
- */
-
-#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
-
-/*
- * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
- * This seems a good reason to start with NumLock off. On HIL keyboards
- * of PARISC machines however there is no NumLock key and everyone expects the keypad
- * to be used for numbers.
- */
-
-#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
-#define KBD_DEFLEDS (1 << VC_NUMLOCK)
-#else
-#define KBD_DEFLEDS 0
-#endif
-
-#define KBD_DEFLOCK 0
-
-void compute_shiftstate(void);
-
-/*
- * Handler Tables.
- */
-
-#define K_HANDLERS\
-       k_self,         k_fn,           k_spec,         k_pad,\
-       k_dead,         k_cons,         k_cur,          k_shift,\
-       k_meta,         k_ascii,        k_lock,         k_lowercase,\
-       k_slock,        k_dead2,        k_brl,          k_ignore
-
-typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value,
-                           char up_flag);
-static k_handler_fn K_HANDLERS;
-static k_handler_fn *k_handler[16] = { K_HANDLERS };
-
-#define FN_HANDLERS\
-       fn_null,        fn_enter,       fn_show_ptregs, fn_show_mem,\
-       fn_show_state,  fn_send_intr,   fn_lastcons,    fn_caps_toggle,\
-       fn_num,         fn_hold,        fn_scroll_forw, fn_scroll_back,\
-       fn_boot_it,     fn_caps_on,     fn_compose,     fn_SAK,\
-       fn_dec_console, fn_inc_console, fn_spawn_con,   fn_bare_num
-
-typedef void (fn_handler_fn)(struct vc_data *vc);
-static fn_handler_fn FN_HANDLERS;
-static fn_handler_fn *fn_handler[] = { FN_HANDLERS };
-
-/*
- * Variables exported for vt_ioctl.c
- */
-
-/* maximum values each key_handler can handle */
-const int max_vals[] = {
-       255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1,
-       NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1,
-       255, NR_LOCK - 1, 255, NR_BRL - 1
-};
-
-const int NR_TYPES = ARRAY_SIZE(max_vals);
-
-struct kbd_struct kbd_table[MAX_NR_CONSOLES];
-EXPORT_SYMBOL_GPL(kbd_table);
-static struct kbd_struct *kbd = kbd_table;
-
-struct vt_spawn_console vt_spawn_con = {
-       .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock),
-       .pid  = NULL,
-       .sig  = 0,
-};
-
-/*
- * Variables exported for vt.c
- */
-
-int shift_state = 0;
-
-/*
- * Internal Data.
- */
-
-static struct input_handler kbd_handler;
-static DEFINE_SPINLOCK(kbd_event_lock);
-static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */
-static unsigned char shift_down[NR_SHIFT];             /* shift state counters.. */
-static bool dead_key_next;
-static int npadch = -1;                                        /* -1 or number assembled on pad */
-static unsigned int diacr;
-static char rep;                                       /* flag telling character repeat */
-
-static unsigned char ledstate = 0xff;                  /* undefined */
-static unsigned char ledioctl;
-
-static struct ledptr {
-       unsigned int *addr;
-       unsigned int mask;
-       unsigned char valid:1;
-} ledptrs[3];
-
-/*
- * Notifier list for console keyboard events
- */
-static ATOMIC_NOTIFIER_HEAD(keyboard_notifier_list);
-
-int register_keyboard_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_register(&keyboard_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(register_keyboard_notifier);
-
-int unregister_keyboard_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_unregister(&keyboard_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_keyboard_notifier);
-
-/*
- * Translation of scancodes to keycodes. We set them on only the first
- * keyboard in the list that accepts the scancode and keycode.
- * Explanation for not choosing the first attached keyboard anymore:
- *  USB keyboards for example have two event devices: one for all "normal"
- *  keys and one for extra function keys (like "volume up", "make coffee",
- *  etc.). So this means that scancodes for the extra function keys won't
- *  be valid for the first event device, but will be for the second.
- */
-
-struct getset_keycode_data {
-       struct input_keymap_entry ke;
-       int error;
-};
-
-static int getkeycode_helper(struct input_handle *handle, void *data)
-{
-       struct getset_keycode_data *d = data;
-
-       d->error = input_get_keycode(handle->dev, &d->ke);
-
-       return d->error == 0; /* stop as soon as we successfully get one */
-}
-
-int getkeycode(unsigned int scancode)
-{
-       struct getset_keycode_data d = {
-               .ke     = {
-                       .flags          = 0,
-                       .len            = sizeof(scancode),
-                       .keycode        = 0,
-               },
-               .error  = -ENODEV,
-       };
-
-       memcpy(d.ke.scancode, &scancode, sizeof(scancode));
-
-       input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper);
-
-       return d.error ?: d.ke.keycode;
-}
-
-static int setkeycode_helper(struct input_handle *handle, void *data)
-{
-       struct getset_keycode_data *d = data;
-
-       d->error = input_set_keycode(handle->dev, &d->ke);
-
-       return d->error == 0; /* stop as soon as we successfully set one */
-}
-
-int setkeycode(unsigned int scancode, unsigned int keycode)
-{
-       struct getset_keycode_data d = {
-               .ke     = {
-                       .flags          = 0,
-                       .len            = sizeof(scancode),
-                       .keycode        = keycode,
-               },
-               .error  = -ENODEV,
-       };
-
-       memcpy(d.ke.scancode, &scancode, sizeof(scancode));
-
-       input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper);
-
-       return d.error;
-}
-
-/*
- * Making beeps and bells. Note that we prefer beeps to bells, but when
- * shutting the sound off we do both.
- */
-
-static int kd_sound_helper(struct input_handle *handle, void *data)
-{
-       unsigned int *hz = data;
-       struct input_dev *dev = handle->dev;
-
-       if (test_bit(EV_SND, dev->evbit)) {
-               if (test_bit(SND_TONE, dev->sndbit)) {
-                       input_inject_event(handle, EV_SND, SND_TONE, *hz);
-                       if (*hz)
-                               return 0;
-               }
-               if (test_bit(SND_BELL, dev->sndbit))
-                       input_inject_event(handle, EV_SND, SND_BELL, *hz ? 1 : 0);
-       }
-
-       return 0;
-}
-
-static void kd_nosound(unsigned long ignored)
-{
-       static unsigned int zero;
-
-       input_handler_for_each_handle(&kbd_handler, &zero, kd_sound_helper);
-}
-
-static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0);
-
-void kd_mksound(unsigned int hz, unsigned int ticks)
-{
-       del_timer_sync(&kd_mksound_timer);
-
-       input_handler_for_each_handle(&kbd_handler, &hz, kd_sound_helper);
-
-       if (hz && ticks)
-               mod_timer(&kd_mksound_timer, jiffies + ticks);
-}
-EXPORT_SYMBOL(kd_mksound);
-
-/*
- * Setting the keyboard rate.
- */
-
-static int kbd_rate_helper(struct input_handle *handle, void *data)
-{
-       struct input_dev *dev = handle->dev;
-       struct kbd_repeat *rep = data;
-
-       if (test_bit(EV_REP, dev->evbit)) {
-
-               if (rep[0].delay > 0)
-                       input_inject_event(handle,
-                                          EV_REP, REP_DELAY, rep[0].delay);
-               if (rep[0].period > 0)
-                       input_inject_event(handle,
-                                          EV_REP, REP_PERIOD, rep[0].period);
-
-               rep[1].delay = dev->rep[REP_DELAY];
-               rep[1].period = dev->rep[REP_PERIOD];
-       }
-
-       return 0;
-}
-
-int kbd_rate(struct kbd_repeat *rep)
-{
-       struct kbd_repeat data[2] = { *rep };
-
-       input_handler_for_each_handle(&kbd_handler, data, kbd_rate_helper);
-       *rep = data[1]; /* Copy currently used settings */
-
-       return 0;
-}
-
-/*
- * Helper Functions.
- */
-static void put_queue(struct vc_data *vc, int ch)
-{
-       struct tty_struct *tty = vc->port.tty;
-
-       if (tty) {
-               tty_insert_flip_char(tty, ch, 0);
-               con_schedule_flip(tty);
-       }
-}
-
-static void puts_queue(struct vc_data *vc, char *cp)
-{
-       struct tty_struct *tty = vc->port.tty;
-
-       if (!tty)
-               return;
-
-       while (*cp) {
-               tty_insert_flip_char(tty, *cp, 0);
-               cp++;
-       }
-       con_schedule_flip(tty);
-}
-
-static void applkey(struct vc_data *vc, int key, char mode)
-{
-       static char buf[] = { 0x1b, 'O', 0x00, 0x00 };
-
-       buf[1] = (mode ? 'O' : '[');
-       buf[2] = key;
-       puts_queue(vc, buf);
-}
-
-/*
- * Many other routines do put_queue, but I think either
- * they produce ASCII, or they produce some user-assigned
- * string, and in both cases we might assume that it is
- * in utf-8 already.
- */
-static void to_utf8(struct vc_data *vc, uint c)
-{
-       if (c < 0x80)
-               /*  0******* */
-               put_queue(vc, c);
-       else if (c < 0x800) {
-               /* 110***** 10****** */
-               put_queue(vc, 0xc0 | (c >> 6));
-               put_queue(vc, 0x80 | (c & 0x3f));
-       } else if (c < 0x10000) {
-               if (c >= 0xD800 && c < 0xE000)
-                       return;
-               if (c == 0xFFFF)
-                       return;
-               /* 1110**** 10****** 10****** */
-               put_queue(vc, 0xe0 | (c >> 12));
-               put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
-               put_queue(vc, 0x80 | (c & 0x3f));
-       } else if (c < 0x110000) {
-               /* 11110*** 10****** 10****** 10****** */
-               put_queue(vc, 0xf0 | (c >> 18));
-               put_queue(vc, 0x80 | ((c >> 12) & 0x3f));
-               put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
-               put_queue(vc, 0x80 | (c & 0x3f));
-       }
-}
-
-/*
- * Called after returning from RAW mode or when changing consoles - recompute
- * shift_down[] and shift_state from key_down[] maybe called when keymap is
- * undefined, so that shiftkey release is seen
- */
-void compute_shiftstate(void)
-{
-       unsigned int i, j, k, sym, val;
-
-       shift_state = 0;
-       memset(shift_down, 0, sizeof(shift_down));
-
-       for (i = 0; i < ARRAY_SIZE(key_down); i++) {
-
-               if (!key_down[i])
-                       continue;
-
-               k = i * BITS_PER_LONG;
-
-               for (j = 0; j < BITS_PER_LONG; j++, k++) {
-
-                       if (!test_bit(k, key_down))
-                               continue;
-
-                       sym = U(key_maps[0][k]);
-                       if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK)
-                               continue;
-
-                       val = KVAL(sym);
-                       if (val == KVAL(K_CAPSSHIFT))
-                               val = KVAL(K_SHIFT);
-
-                       shift_down[val]++;
-                       shift_state |= (1 << val);
-               }
-       }
-}
-
-/*
- * We have a combining character DIACR here, followed by the character CH.
- * If the combination occurs in the table, return the corresponding value.
- * Otherwise, if CH is a space or equals DIACR, return DIACR.
- * Otherwise, conclude that DIACR was not combining after all,
- * queue it and return CH.
- */
-static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch)
-{
-       unsigned int d = diacr;
-       unsigned int i;
-
-       diacr = 0;
-
-       if ((d & ~0xff) == BRL_UC_ROW) {
-               if ((ch & ~0xff) == BRL_UC_ROW)
-                       return d | ch;
-       } else {
-               for (i = 0; i < accent_table_size; i++)
-                       if (accent_table[i].diacr == d && accent_table[i].base == ch)
-                               return accent_table[i].result;
-       }
-
-       if (ch == ' ' || ch == (BRL_UC_ROW|0) || ch == d)
-               return d;
-
-       if (kbd->kbdmode == VC_UNICODE)
-               to_utf8(vc, d);
-       else {
-               int c = conv_uni_to_8bit(d);
-               if (c != -1)
-                       put_queue(vc, c);
-       }
-
-       return ch;
-}
-
-/*
- * Special function handlers
- */
-static void fn_enter(struct vc_data *vc)
-{
-       if (diacr) {
-               if (kbd->kbdmode == VC_UNICODE)
-                       to_utf8(vc, diacr);
-               else {
-                       int c = conv_uni_to_8bit(diacr);
-                       if (c != -1)
-                               put_queue(vc, c);
-               }
-               diacr = 0;
-       }
-
-       put_queue(vc, 13);
-       if (vc_kbd_mode(kbd, VC_CRLF))
-               put_queue(vc, 10);
-}
-
-static void fn_caps_toggle(struct vc_data *vc)
-{
-       if (rep)
-               return;
-
-       chg_vc_kbd_led(kbd, VC_CAPSLOCK);
-}
-
-static void fn_caps_on(struct vc_data *vc)
-{
-       if (rep)
-               return;
-
-       set_vc_kbd_led(kbd, VC_CAPSLOCK);
-}
-
-static void fn_show_ptregs(struct vc_data *vc)
-{
-       struct pt_regs *regs = get_irq_regs();
-
-       if (regs)
-               show_regs(regs);
-}
-
-static void fn_hold(struct vc_data *vc)
-{
-       struct tty_struct *tty = vc->port.tty;
-
-       if (rep || !tty)
-               return;
-
-       /*
-        * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty);
-        * these routines are also activated by ^S/^Q.
-        * (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
-        */
-       if (tty->stopped)
-               start_tty(tty);
-       else
-               stop_tty(tty);
-}
-
-static void fn_num(struct vc_data *vc)
-{
-       if (vc_kbd_mode(kbd, VC_APPLIC))
-               applkey(vc, 'P', 1);
-       else
-               fn_bare_num(vc);
-}
-
-/*
- * Bind this to Shift-NumLock if you work in application keypad mode
- * but want to be able to change the NumLock flag.
- * Bind this to NumLock if you prefer that the NumLock key always
- * changes the NumLock flag.
- */
-static void fn_bare_num(struct vc_data *vc)
-{
-       if (!rep)
-               chg_vc_kbd_led(kbd, VC_NUMLOCK);
-}
-
-static void fn_lastcons(struct vc_data *vc)
-{
-       /* switch to the last used console, ChN */
-       set_console(last_console);
-}
-
-static void fn_dec_console(struct vc_data *vc)
-{
-       int i, cur = fg_console;
-
-       /* Currently switching?  Queue this next switch relative to that. */
-       if (want_console != -1)
-               cur = want_console;
-
-       for (i = cur - 1; i != cur; i--) {
-               if (i == -1)
-                       i = MAX_NR_CONSOLES - 1;
-               if (vc_cons_allocated(i))
-                       break;
-       }
-       set_console(i);
-}
-
-static void fn_inc_console(struct vc_data *vc)
-{
-       int i, cur = fg_console;
-
-       /* Currently switching?  Queue this next switch relative to that. */
-       if (want_console != -1)
-               cur = want_console;
-
-       for (i = cur+1; i != cur; i++) {
-               if (i == MAX_NR_CONSOLES)
-                       i = 0;
-               if (vc_cons_allocated(i))
-                       break;
-       }
-       set_console(i);
-}
-
-static void fn_send_intr(struct vc_data *vc)
-{
-       struct tty_struct *tty = vc->port.tty;
-
-       if (!tty)
-               return;
-       tty_insert_flip_char(tty, 0, TTY_BREAK);
-       con_schedule_flip(tty);
-}
-
-static void fn_scroll_forw(struct vc_data *vc)
-{
-       scrollfront(vc, 0);
-}
-
-static void fn_scroll_back(struct vc_data *vc)
-{
-       scrollback(vc, 0);
-}
-
-static void fn_show_mem(struct vc_data *vc)
-{
-       show_mem();
-}
-
-static void fn_show_state(struct vc_data *vc)
-{
-       show_state();
-}
-
-static void fn_boot_it(struct vc_data *vc)
-{
-       ctrl_alt_del();
-}
-
-static void fn_compose(struct vc_data *vc)
-{
-       dead_key_next = true;
-}
-
-static void fn_spawn_con(struct vc_data *vc)
-{
-       spin_lock(&vt_spawn_con.lock);
-       if (vt_spawn_con.pid)
-               if (kill_pid(vt_spawn_con.pid, vt_spawn_con.sig, 1)) {
-                       put_pid(vt_spawn_con.pid);
-                       vt_spawn_con.pid = NULL;
-               }
-       spin_unlock(&vt_spawn_con.lock);
-}
-
-static void fn_SAK(struct vc_data *vc)
-{
-       struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
-       schedule_work(SAK_work);
-}
-
-static void fn_null(struct vc_data *vc)
-{
-       compute_shiftstate();
-}
-
-/*
- * Special key handlers
- */
-static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag)
-{
-}
-
-static void k_spec(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       if (up_flag)
-               return;
-       if (value >= ARRAY_SIZE(fn_handler))
-               return;
-       if ((kbd->kbdmode == VC_RAW ||
-            kbd->kbdmode == VC_MEDIUMRAW) &&
-            value != KVAL(K_SAK))
-               return;         /* SAK is allowed even in raw mode */
-       fn_handler[value](vc);
-}
-
-static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       pr_err("k_lowercase was called - impossible\n");
-}
-
-static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag)
-{
-       if (up_flag)
-               return;         /* no action, if this is a key release */
-
-       if (diacr)
-               value = handle_diacr(vc, value);
-
-       if (dead_key_next) {
-               dead_key_next = false;
-               diacr = value;
-               return;
-       }
-       if (kbd->kbdmode == VC_UNICODE)
-               to_utf8(vc, value);
-       else {
-               int c = conv_uni_to_8bit(value);
-               if (c != -1)
-                       put_queue(vc, c);
-       }
-}
-
-/*
- * Handle dead key. Note that we now may have several
- * dead keys modifying the same character. Very useful
- * for Vietnamese.
- */
-static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag)
-{
-       if (up_flag)
-               return;
-
-       diacr = (diacr ? handle_diacr(vc, value) : value);
-}
-
-static void k_self(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       k_unicode(vc, conv_8bit_to_uni(value), up_flag);
-}
-
-static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       k_deadunicode(vc, value, up_flag);
-}
-
-/*
- * Obsolete - for backwards compatibility only
- */
-static void k_dead(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
-
-       k_deadunicode(vc, ret_diacr[value], up_flag);
-}
-
-static void k_cons(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       if (up_flag)
-               return;
-
-       set_console(value);
-}
-
-static void k_fn(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       if (up_flag)
-               return;
-
-       if ((unsigned)value < ARRAY_SIZE(func_table)) {
-               if (func_table[value])
-                       puts_queue(vc, func_table[value]);
-       } else
-               pr_err("k_fn called with value=%d\n", value);
-}
-
-static void k_cur(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       static const char cur_chars[] = "BDCA";
-
-       if (up_flag)
-               return;
-
-       applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE));
-}
-
-static void k_pad(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       static const char pad_chars[] = "0123456789+-*/\015,.?()#";
-       static const char app_map[] = "pqrstuvwxylSRQMnnmPQS";
-
-       if (up_flag)
-               return;         /* no action, if this is a key release */
-
-       /* kludge... shift forces cursor/number keys */
-       if (vc_kbd_mode(kbd, VC_APPLIC) && !shift_down[KG_SHIFT]) {
-               applkey(vc, app_map[value], 1);
-               return;
-       }
-
-       if (!vc_kbd_led(kbd, VC_NUMLOCK)) {
-
-               switch (value) {
-               case KVAL(K_PCOMMA):
-               case KVAL(K_PDOT):
-                       k_fn(vc, KVAL(K_REMOVE), 0);
-                       return;
-               case KVAL(K_P0):
-                       k_fn(vc, KVAL(K_INSERT), 0);
-                       return;
-               case KVAL(K_P1):
-                       k_fn(vc, KVAL(K_SELECT), 0);
-                       return;
-               case KVAL(K_P2):
-                       k_cur(vc, KVAL(K_DOWN), 0);
-                       return;
-               case KVAL(K_P3):
-                       k_fn(vc, KVAL(K_PGDN), 0);
-                       return;
-               case KVAL(K_P4):
-                       k_cur(vc, KVAL(K_LEFT), 0);
-                       return;
-               case KVAL(K_P6):
-                       k_cur(vc, KVAL(K_RIGHT), 0);
-                       return;
-               case KVAL(K_P7):
-                       k_fn(vc, KVAL(K_FIND), 0);
-                       return;
-               case KVAL(K_P8):
-                       k_cur(vc, KVAL(K_UP), 0);
-                       return;
-               case KVAL(K_P9):
-                       k_fn(vc, KVAL(K_PGUP), 0);
-                       return;
-               case KVAL(K_P5):
-                       applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC));
-                       return;
-               }
-       }
-
-       put_queue(vc, pad_chars[value]);
-       if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
-               put_queue(vc, 10);
-}
-
-static void k_shift(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       int old_state = shift_state;
-
-       if (rep)
-               return;
-       /*
-        * Mimic typewriter:
-        * a CapsShift key acts like Shift but undoes CapsLock
-        */
-       if (value == KVAL(K_CAPSSHIFT)) {
-               value = KVAL(K_SHIFT);
-               if (!up_flag)
-                       clr_vc_kbd_led(kbd, VC_CAPSLOCK);
-       }
-
-       if (up_flag) {
-               /*
-                * handle the case that two shift or control
-                * keys are depressed simultaneously
-                */
-               if (shift_down[value])
-                       shift_down[value]--;
-       } else
-               shift_down[value]++;
-
-       if (shift_down[value])
-               shift_state |= (1 << value);
-       else
-               shift_state &= ~(1 << value);
-
-       /* kludge */
-       if (up_flag && shift_state != old_state && npadch != -1) {
-               if (kbd->kbdmode == VC_UNICODE)
-                       to_utf8(vc, npadch);
-               else
-                       put_queue(vc, npadch & 0xff);
-               npadch = -1;
-       }
-}
-
-static void k_meta(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       if (up_flag)
-               return;
-
-       if (vc_kbd_mode(kbd, VC_META)) {
-               put_queue(vc, '\033');
-               put_queue(vc, value);
-       } else
-               put_queue(vc, value | 0x80);
-}
-
-static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       int base;
-
-       if (up_flag)
-               return;
-
-       if (value < 10) {
-               /* decimal input of code, while Alt depressed */
-               base = 10;
-       } else {
-               /* hexadecimal input of code, while AltGr depressed */
-               value -= 10;
-               base = 16;
-       }
-
-       if (npadch == -1)
-               npadch = value;
-       else
-               npadch = npadch * base + value;
-}
-
-static void k_lock(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       if (up_flag || rep)
-               return;
-
-       chg_vc_kbd_lock(kbd, value);
-}
-
-static void k_slock(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       k_shift(vc, value, up_flag);
-       if (up_flag || rep)
-               return;
-
-       chg_vc_kbd_slock(kbd, value);
-       /* try to make Alt, oops, AltGr and such work */
-       if (!key_maps[kbd->lockstate ^ kbd->slockstate]) {
-               kbd->slockstate = 0;
-               chg_vc_kbd_slock(kbd, value);
-       }
-}
-
-/* by default, 300ms interval for combination release */
-static unsigned brl_timeout = 300;
-MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for commit on first key release)");
-module_param(brl_timeout, uint, 0644);
-
-static unsigned brl_nbchords = 1;
-MODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)");
-module_param(brl_nbchords, uint, 0644);
-
-static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag)
-{
-       static unsigned long chords;
-       static unsigned committed;
-
-       if (!brl_nbchords)
-               k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag);
-       else {
-               committed |= pattern;
-               chords++;
-               if (chords == brl_nbchords) {
-                       k_unicode(vc, BRL_UC_ROW | committed, up_flag);
-                       chords = 0;
-                       committed = 0;
-               }
-       }
-}
-
-static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
-{
-       static unsigned pressed, committing;
-       static unsigned long releasestart;
-
-       if (kbd->kbdmode != VC_UNICODE) {
-               if (!up_flag)
-                       pr_warning("keyboard mode must be unicode for braille patterns\n");
-               return;
-       }
-
-       if (!value) {
-               k_unicode(vc, BRL_UC_ROW, up_flag);
-               return;
-       }
-
-       if (value > 8)
-               return;
-
-       if (!up_flag) {
-               pressed |= 1 << (value - 1);
-               if (!brl_timeout)
-                       committing = pressed;
-       } else if (brl_timeout) {
-               if (!committing ||
-                   time_after(jiffies,
-                              releasestart + msecs_to_jiffies(brl_timeout))) {
-                       committing = pressed;
-                       releasestart = jiffies;
-               }
-               pressed &= ~(1 << (value - 1));
-               if (!pressed && committing) {
-                       k_brlcommit(vc, committing, 0);
-                       committing = 0;
-               }
-       } else {
-               if (committing) {
-                       k_brlcommit(vc, committing, 0);
-                       committing = 0;
-               }
-               pressed &= ~(1 << (value - 1));
-       }
-}
-
-/*
- * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
- * or (ii) whatever pattern of lights people want to show using KDSETLED,
- * or (iii) specified bits of specified words in kernel memory.
- */
-unsigned char getledstate(void)
-{
-       return ledstate;
-}
-
-void setledstate(struct kbd_struct *kbd, unsigned int led)
-{
-       if (!(led & ~7)) {
-               ledioctl = led;
-               kbd->ledmode = LED_SHOW_IOCTL;
-       } else
-               kbd->ledmode = LED_SHOW_FLAGS;
-
-       set_leds();
-}
-
-static inline unsigned char getleds(void)
-{
-       struct kbd_struct *kbd = kbd_table + fg_console;
-       unsigned char leds;
-       int i;
-
-       if (kbd->ledmode == LED_SHOW_IOCTL)
-               return ledioctl;
-
-       leds = kbd->ledflagstate;
-
-       if (kbd->ledmode == LED_SHOW_MEM) {
-               for (i = 0; i < 3; i++)
-                       if (ledptrs[i].valid) {
-                               if (*ledptrs[i].addr & ledptrs[i].mask)
-                                       leds |= (1 << i);
-                               else
-                                       leds &= ~(1 << i);
-                       }
-       }
-       return leds;
-}
-
-static int kbd_update_leds_helper(struct input_handle *handle, void *data)
-{
-       unsigned char leds = *(unsigned char *)data;
-
-       if (test_bit(EV_LED, handle->dev->evbit)) {
-               input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
-               input_inject_event(handle, EV_LED, LED_NUML,    !!(leds & 0x02));
-               input_inject_event(handle, EV_LED, LED_CAPSL,   !!(leds & 0x04));
-               input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
-       }
-
-       return 0;
-}
-
-/*
- * This is the tasklet that updates LED state on all keyboards
- * attached to the box. The reason we use tasklet is that we
- * need to handle the scenario when keyboard handler is not
- * registered yet but we already getting updates form VT to
- * update led state.
- */
-static void kbd_bh(unsigned long dummy)
-{
-       unsigned char leds = getleds();
-
-       if (leds != ledstate) {
-               input_handler_for_each_handle(&kbd_handler, &leds,
-                                             kbd_update_leds_helper);
-               ledstate = leds;
-       }
-}
-
-DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
-
-#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
-    defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
-    defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
-    (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) ||\
-    defined(CONFIG_AVR32)
-
-#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
-                       ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
-
-static const unsigned short x86_keycodes[256] =
-       { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
-        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
-        32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
-        48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-        64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
-        80, 81, 82, 83, 84,118, 86, 87, 88,115,120,119,121,112,123, 92,
-       284,285,309,  0,312, 91,327,328,329,331,333,335,336,337,338,339,
-       367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349,
-       360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355,
-       103,104,105,275,287,279,258,106,274,107,294,364,358,363,362,361,
-       291,108,381,281,290,272,292,305,280, 99,112,257,306,359,113,114,
-       264,117,271,374,379,265,266, 93, 94, 95, 85,259,375,260, 90,116,
-       377,109,111,277,278,282,283,295,296,297,299,300,301,293,303,307,
-       308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330,
-       332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 };
-
-#ifdef CONFIG_SPARC
-static int sparc_l1_a_state;
-extern void sun_do_break(void);
-#endif
-
-static int emulate_raw(struct vc_data *vc, unsigned int keycode,
-                      unsigned char up_flag)
-{
-       int code;
-
-       switch (keycode) {
-
-       case KEY_PAUSE:
-               put_queue(vc, 0xe1);
-               put_queue(vc, 0x1d | up_flag);
-               put_queue(vc, 0x45 | up_flag);
-               break;
-
-       case KEY_HANGEUL:
-               if (!up_flag)
-                       put_queue(vc, 0xf2);
-               break;
-
-       case KEY_HANJA:
-               if (!up_flag)
-                       put_queue(vc, 0xf1);
-               break;
-
-       case KEY_SYSRQ:
-               /*
-                * Real AT keyboards (that's what we're trying
-                * to emulate here emit 0xe0 0x2a 0xe0 0x37 when
-                * pressing PrtSc/SysRq alone, but simply 0x54
-                * when pressing Alt+PrtSc/SysRq.
-                */
-               if (test_bit(KEY_LEFTALT, key_down) ||
-                   test_bit(KEY_RIGHTALT, key_down)) {
-                       put_queue(vc, 0x54 | up_flag);
-               } else {
-                       put_queue(vc, 0xe0);
-                       put_queue(vc, 0x2a | up_flag);
-                       put_queue(vc, 0xe0);
-                       put_queue(vc, 0x37 | up_flag);
-               }
-               break;
-
-       default:
-               if (keycode > 255)
-                       return -1;
-
-               code = x86_keycodes[keycode];
-               if (!code)
-                       return -1;
-
-               if (code & 0x100)
-                       put_queue(vc, 0xe0);
-               put_queue(vc, (code & 0x7f) | up_flag);
-
-               break;
-       }
-
-       return 0;
-}
-
-#else
-
-#define HW_RAW(dev)    0
-
-static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag)
-{
-       if (keycode > 127)
-               return -1;
-
-       put_queue(vc, keycode | up_flag);
-       return 0;
-}
-#endif
-
-static void kbd_rawcode(unsigned char data)
-{
-       struct vc_data *vc = vc_cons[fg_console].d;
-
-       kbd = kbd_table + vc->vc_num;
-       if (kbd->kbdmode == VC_RAW)
-               put_queue(vc, data);
-}
-
-static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
-{
-       struct vc_data *vc = vc_cons[fg_console].d;
-       unsigned short keysym, *key_map;
-       unsigned char type;
-       bool raw_mode;
-       struct tty_struct *tty;
-       int shift_final;
-       struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down };
-       int rc;
-
-       tty = vc->port.tty;
-
-       if (tty && (!tty->driver_data)) {
-               /* No driver data? Strange. Okay we fix it then. */
-               tty->driver_data = vc;
-       }
-
-       kbd = kbd_table + vc->vc_num;
-
-#ifdef CONFIG_SPARC
-       if (keycode == KEY_STOP)
-               sparc_l1_a_state = down;
-#endif
-
-       rep = (down == 2);
-
-       raw_mode = (kbd->kbdmode == VC_RAW);
-       if (raw_mode && !hw_raw)
-               if (emulate_raw(vc, keycode, !down << 7))
-                       if (keycode < BTN_MISC && printk_ratelimit())
-                               pr_warning("can't emulate rawmode for keycode %d\n",
-                                          keycode);
-
-#ifdef CONFIG_SPARC
-       if (keycode == KEY_A && sparc_l1_a_state) {
-               sparc_l1_a_state = false;
-               sun_do_break();
-       }
-#endif
-
-       if (kbd->kbdmode == VC_MEDIUMRAW) {
-               /*
-                * This is extended medium raw mode, with keys above 127
-                * encoded as 0, high 7 bits, low 7 bits, with the 0 bearing
-                * the 'up' flag if needed. 0 is reserved, so this shouldn't
-                * interfere with anything else. The two bytes after 0 will
-                * always have the up flag set not to interfere with older
-                * applications. This allows for 16384 different keycodes,
-                * which should be enough.
-                */
-               if (keycode < 128) {
-                       put_queue(vc, keycode | (!down << 7));
-               } else {
-                       put_queue(vc, !down << 7);
-                       put_queue(vc, (keycode >> 7) | 0x80);
-                       put_queue(vc, keycode | 0x80);
-               }
-               raw_mode = true;
-       }
-
-       if (down)
-               set_bit(keycode, key_down);
-       else
-               clear_bit(keycode, key_down);
-
-       if (rep &&
-           (!vc_kbd_mode(kbd, VC_REPEAT) ||
-            (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) {
-               /*
-                * Don't repeat a key if the input buffers are not empty and the
-                * characters get aren't echoed locally. This makes key repeat
-                * usable with slow applications and under heavy loads.
-                */
-               return;
-       }
-
-       param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate;
-       param.ledstate = kbd->ledflagstate;
-       key_map = key_maps[shift_final];
-
-       rc = atomic_notifier_call_chain(&keyboard_notifier_list,
-                                       KBD_KEYCODE, &param);
-       if (rc == NOTIFY_STOP || !key_map) {
-               atomic_notifier_call_chain(&keyboard_notifier_list,
-                                          KBD_UNBOUND_KEYCODE, &param);
-               compute_shiftstate();
-               kbd->slockstate = 0;
-               return;
-       }
-
-       if (keycode < NR_KEYS)
-               keysym = key_map[keycode];
-       else if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8)
-               keysym = U(K(KT_BRL, keycode - KEY_BRL_DOT1 + 1));
-       else
-               return;
-
-       type = KTYP(keysym);
-
-       if (type < 0xf0) {
-               param.value = keysym;
-               rc = atomic_notifier_call_chain(&keyboard_notifier_list,
-                                               KBD_UNICODE, &param);
-               if (rc != NOTIFY_STOP)
-                       if (down && !raw_mode)
-                               to_utf8(vc, keysym);
-               return;
-       }
-
-       type -= 0xf0;
-
-       if (type == KT_LETTER) {
-               type = KT_LATIN;
-               if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
-                       key_map = key_maps[shift_final ^ (1 << KG_SHIFT)];
-                       if (key_map)
-                               keysym = key_map[keycode];
-               }
-       }
-
-       param.value = keysym;
-       rc = atomic_notifier_call_chain(&keyboard_notifier_list,
-                                       KBD_KEYSYM, &param);
-       if (rc == NOTIFY_STOP)
-               return;
-
-       if (raw_mode && type != KT_SPEC && type != KT_SHIFT)
-               return;
-
-       (*k_handler[type])(vc, keysym & 0xff, !down);
-
-       param.ledstate = kbd->ledflagstate;
-       atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, &param);
-
-       if (type != KT_SLOCK)
-               kbd->slockstate = 0;
-}
-
-static void kbd_event(struct input_handle *handle, unsigned int event_type,
-                     unsigned int event_code, int value)
-{
-       /* We are called with interrupts disabled, just take the lock */
-       spin_lock(&kbd_event_lock);
-
-       if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
-               kbd_rawcode(value);
-       if (event_type == EV_KEY)
-               kbd_keycode(event_code, value, HW_RAW(handle->dev));
-
-       spin_unlock(&kbd_event_lock);
-
-       tasklet_schedule(&keyboard_tasklet);
-       do_poke_blanked_console = 1;
-       schedule_console_callback();
-}
-
-static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
-{
-       int i;
-
-       if (test_bit(EV_SND, dev->evbit))
-               return true;
-
-       if (test_bit(EV_KEY, dev->evbit)) {
-               for (i = KEY_RESERVED; i < BTN_MISC; i++)
-                       if (test_bit(i, dev->keybit))
-                               return true;
-               for (i = KEY_BRL_DOT1; i <= KEY_BRL_DOT10; i++)
-                       if (test_bit(i, dev->keybit))
-                               return true;
-       }
-
-       return false;
-}
-
-/*
- * When a keyboard (or other input device) is found, the kbd_connect
- * function is called. The function then looks at the device, and if it
- * likes it, it can open it and get events from it. In this (kbd_connect)
- * function, we should decide which VT to bind that keyboard to initially.
- */
-static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
-                       const struct input_device_id *id)
-{
-       struct input_handle *handle;
-       int error;
-
-       handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
-       if (!handle)
-               return -ENOMEM;
-
-       handle->dev = dev;
-       handle->handler = handler;
-       handle->name = "kbd";
-
-       error = input_register_handle(handle);
-       if (error)
-               goto err_free_handle;
-
-       error = input_open_device(handle);
-       if (error)
-               goto err_unregister_handle;
-
-       return 0;
-
- err_unregister_handle:
-       input_unregister_handle(handle);
- err_free_handle:
-       kfree(handle);
-       return error;
-}
-
-static void kbd_disconnect(struct input_handle *handle)
-{
-       input_close_device(handle);
-       input_unregister_handle(handle);
-       kfree(handle);
-}
-
-/*
- * Start keyboard handler on the new keyboard by refreshing LED state to
- * match the rest of the system.
- */
-static void kbd_start(struct input_handle *handle)
-{
-       tasklet_disable(&keyboard_tasklet);
-
-       if (ledstate != 0xff)
-               kbd_update_leds_helper(handle, &ledstate);
-
-       tasklet_enable(&keyboard_tasklet);
-}
-
-static const struct input_device_id kbd_ids[] = {
-       {
-                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-                .evbit = { BIT_MASK(EV_KEY) },
-        },
-
-       {
-                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
-                .evbit = { BIT_MASK(EV_SND) },
-        },
-
-       { },    /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(input, kbd_ids);
-
-static struct input_handler kbd_handler = {
-       .event          = kbd_event,
-       .match          = kbd_match,
-       .connect        = kbd_connect,
-       .disconnect     = kbd_disconnect,
-       .start          = kbd_start,
-       .name           = "kbd",
-       .id_table       = kbd_ids,
-};
-
-int __init kbd_init(void)
-{
-       int i;
-       int error;
-
-        for (i = 0; i < MAX_NR_CONSOLES; i++) {
-               kbd_table[i].ledflagstate = KBD_DEFLEDS;
-               kbd_table[i].default_ledflagstate = KBD_DEFLEDS;
-               kbd_table[i].ledmode = LED_SHOW_FLAGS;
-               kbd_table[i].lockstate = KBD_DEFLOCK;
-               kbd_table[i].slockstate = 0;
-               kbd_table[i].modeflags = KBD_DEFMODE;
-               kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
-       }
-
-       error = input_register_handler(&kbd_handler);
-       if (error)
-               return error;
-
-       tasklet_enable(&keyboard_tasklet);
-       tasklet_schedule(&keyboard_tasklet);
-
-       return 0;
-}
diff --git a/drivers/char/n_gsm.c b/drivers/char/n_gsm.c
deleted file mode 100644 (file)
index 04ef3ef..0000000
+++ /dev/null
@@ -1,2763 +0,0 @@
-/*
- * n_gsm.c GSM 0710 tty multiplexor
- * Copyright (c) 2009/10 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *     * THIS IS A DEVELOPMENT SNAPSHOT IT IS NOT A FINAL RELEASE *
- *
- * TO DO:
- *     Mostly done:    ioctls for setting modes/timing
- *     Partly done:    hooks so you can pull off frames to non tty devs
- *     Restart DLCI 0 when it closes ?
- *     Test basic encoding
- *     Improve the tx engine
- *     Resolve tx side locking by adding a queue_head and routing
- *             all control traffic via it
- *     General tidy/document
- *     Review the locking/move to refcounts more (mux now moved to an
- *             alloc/free model ready)
- *     Use newest tty open/close port helpers and install hooks
- *     What to do about power functions ?
- *     Termios setting and negotiation
- *     Do we need a 'which mux are you' ioctl to correlate mux and tty sets
- *
- */
-
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/ctype.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/bitops.h>
-#include <linux/file.h>
-#include <linux/uaccess.h>
-#include <linux/module.h>
-#include <linux/timer.h>
-#include <linux/tty_flip.h>
-#include <linux/tty_driver.h>
-#include <linux/serial.h>
-#include <linux/kfifo.h>
-#include <linux/skbuff.h>
-#include <linux/gsmmux.h>
-
-static int debug;
-module_param(debug, int, 0600);
-
-#define T1     (HZ/10)
-#define T2     (HZ/3)
-#define N2     3
-
-/* Use long timers for testing at low speed with debug on */
-#ifdef DEBUG_TIMING
-#define T1     HZ
-#define T2     (2 * HZ)
-#endif
-
-/* Semi-arbitary buffer size limits. 0710 is normally run with 32-64 byte
-   limits so this is plenty */
-#define MAX_MRU 512
-#define MAX_MTU 512
-
-/*
- *     Each block of data we have queued to go out is in the form of
- *     a gsm_msg which holds everything we need in a link layer independant
- *     format
- */
-
-struct gsm_msg {
-       struct gsm_msg *next;
-       u8 addr;                /* DLCI address + flags */
-       u8 ctrl;                /* Control byte + flags */
-       unsigned int len;       /* Length of data block (can be zero) */
-       unsigned char *data;    /* Points into buffer but not at the start */
-       unsigned char buffer[0];
-};
-
-/*
- *     Each active data link has a gsm_dlci structure associated which ties
- *     the link layer to an optional tty (if the tty side is open). To avoid
- *     complexity right now these are only ever freed up when the mux is
- *     shut down.
- *
- *     At the moment we don't free DLCI objects until the mux is torn down
- *     this avoid object life time issues but might be worth review later.
- */
-
-struct gsm_dlci {
-       struct gsm_mux *gsm;
-       int addr;
-       int state;
-#define DLCI_CLOSED            0
-#define DLCI_OPENING           1       /* Sending SABM not seen UA */
-#define DLCI_OPEN              2       /* SABM/UA complete */
-#define DLCI_CLOSING           3       /* Sending DISC not seen UA/DM */
-
-       /* Link layer */
-       spinlock_t lock;        /* Protects the internal state */
-       struct timer_list t1;   /* Retransmit timer for SABM and UA */
-       int retries;
-       /* Uplink tty if active */
-       struct tty_port port;   /* The tty bound to this DLCI if there is one */
-       struct kfifo *fifo;     /* Queue fifo for the DLCI */
-       struct kfifo _fifo;     /* For new fifo API porting only */
-       int adaption;           /* Adaption layer in use */
-       u32 modem_rx;           /* Our incoming virtual modem lines */
-       u32 modem_tx;           /* Our outgoing modem lines */
-       int dead;               /* Refuse re-open */
-       /* Flow control */
-       int throttled;          /* Private copy of throttle state */
-       int constipated;        /* Throttle status for outgoing */
-       /* Packetised I/O */
-       struct sk_buff *skb;    /* Frame being sent */
-       struct sk_buff_head skb_list;   /* Queued frames */
-       /* Data handling callback */
-       void (*data)(struct gsm_dlci *dlci, u8 *data, int len);
-};
-
-/* DLCI 0, 62/63 are special or reseved see gsmtty_open */
-
-#define NUM_DLCI               64
-
-/*
- *     DLCI 0 is used to pass control blocks out of band of the data
- *     flow (and with a higher link priority). One command can be outstanding
- *     at a time and we use this structure to manage them. They are created
- *     and destroyed by the user context, and updated by the receive paths
- *     and timers
- */
-
-struct gsm_control {
-       u8 cmd;         /* Command we are issuing */
-       u8 *data;       /* Data for the command in case we retransmit */
-       int len;        /* Length of block for retransmission */
-       int done;       /* Done flag */
-       int error;      /* Error if any */
-};
-
-/*
- *     Each GSM mux we have is represented by this structure. If we are
- *     operating as an ldisc then we use this structure as our ldisc
- *     state. We need to sort out lifetimes and locking with respect
- *     to the gsm mux array. For now we don't free DLCI objects that
- *     have been instantiated until the mux itself is terminated.
- *
- *     To consider further: tty open versus mux shutdown.
- */
-
-struct gsm_mux {
-       struct tty_struct *tty;         /* The tty our ldisc is bound to */
-       spinlock_t lock;
-
-       /* Events on the GSM channel */
-       wait_queue_head_t event;
-
-       /* Bits for GSM mode decoding */
-
-       /* Framing Layer */
-       unsigned char *buf;
-       int state;
-#define GSM_SEARCH             0
-#define GSM_START              1
-#define GSM_ADDRESS            2
-#define GSM_CONTROL            3
-#define GSM_LEN                        4
-#define GSM_DATA               5
-#define GSM_FCS                        6
-#define GSM_OVERRUN            7
-       unsigned int len;
-       unsigned int address;
-       unsigned int count;
-       int escape;
-       int encoding;
-       u8 control;
-       u8 fcs;
-       u8 *txframe;                    /* TX framing buffer */
-
-       /* Methods for the receiver side */
-       void (*receive)(struct gsm_mux *gsm, u8 ch);
-       void (*error)(struct gsm_mux *gsm, u8 ch, u8 flag);
-       /* And transmit side */
-       int (*output)(struct gsm_mux *mux, u8 *data, int len);
-
-       /* Link Layer */
-       unsigned int mru;
-       unsigned int mtu;
-       int initiator;                  /* Did we initiate connection */
-       int dead;                       /* Has the mux been shut down */
-       struct gsm_dlci *dlci[NUM_DLCI];
-       int constipated;                /* Asked by remote to shut up */
-
-       spinlock_t tx_lock;
-       unsigned int tx_bytes;          /* TX data outstanding */
-#define TX_THRESH_HI           8192
-#define TX_THRESH_LO           2048
-       struct gsm_msg *tx_head;        /* Pending data packets */
-       struct gsm_msg *tx_tail;
-
-       /* Control messages */
-       struct timer_list t2_timer;     /* Retransmit timer for commands */
-       int cretries;                   /* Command retry counter */
-       struct gsm_control *pending_cmd;/* Our current pending command */
-       spinlock_t control_lock;        /* Protects the pending command */
-
-       /* Configuration */
-       int adaption;           /* 1 or 2 supported */
-       u8 ftype;               /* UI or UIH */
-       int t1, t2;             /* Timers in 1/100th of a sec */
-       int n2;                 /* Retry count */
-
-       /* Statistics (not currently exposed) */
-       unsigned long bad_fcs;
-       unsigned long malformed;
-       unsigned long io_error;
-       unsigned long bad_size;
-       unsigned long unsupported;
-};
-
-
-/*
- *     Mux objects - needed so that we can translate a tty index into the
- *     relevant mux and DLCI.
- */
-
-#define MAX_MUX                4                       /* 256 minors */
-static struct gsm_mux *gsm_mux[MAX_MUX];       /* GSM muxes */
-static spinlock_t gsm_mux_lock;
-
-/*
- *     This section of the driver logic implements the GSM encodings
- *     both the basic and the 'advanced'. Reliable transport is not
- *     supported.
- */
-
-#define CR                     0x02
-#define EA                     0x01
-#define        PF                      0x10
-
-/* I is special: the rest are ..*/
-#define RR                     0x01
-#define UI                     0x03
-#define RNR                    0x05
-#define REJ                    0x09
-#define DM                     0x0F
-#define SABM                   0x2F
-#define DISC                   0x43
-#define UA                     0x63
-#define        UIH                     0xEF
-
-/* Channel commands */
-#define CMD_NSC                        0x09
-#define CMD_TEST               0x11
-#define CMD_PSC                        0x21
-#define CMD_RLS                        0x29
-#define CMD_FCOFF              0x31
-#define CMD_PN                 0x41
-#define CMD_RPN                        0x49
-#define CMD_FCON               0x51
-#define CMD_CLD                        0x61
-#define CMD_SNC                        0x69
-#define CMD_MSC                        0x71
-
-/* Virtual modem bits */
-#define MDM_FC                 0x01
-#define MDM_RTC                        0x02
-#define MDM_RTR                        0x04
-#define MDM_IC                 0x20
-#define MDM_DV                 0x40
-
-#define GSM0_SOF               0xF9
-#define GSM1_SOF               0x7E
-#define GSM1_ESCAPE            0x7D
-#define GSM1_ESCAPE_BITS       0x20
-#define XON                    0x11
-#define XOFF                   0x13
-
-static const struct tty_port_operations gsm_port_ops;
-
-/*
- *     CRC table for GSM 0710
- */
-
-static const u8 gsm_fcs8[256] = {
-       0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75,
-       0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
-       0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69,
-       0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
-       0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D,
-       0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
-       0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51,
-       0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
-       0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05,
-       0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
-       0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19,
-       0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
-       0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D,
-       0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
-       0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21,
-       0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
-       0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95,
-       0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
-       0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89,
-       0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
-       0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD,
-       0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
-       0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1,
-       0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
-       0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5,
-       0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
-       0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9,
-       0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
-       0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD,
-       0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
-       0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1,
-       0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
-};
-
-#define INIT_FCS       0xFF
-#define GOOD_FCS       0xCF
-
-/**
- *     gsm_fcs_add     -       update FCS
- *     @fcs: Current FCS
- *     @c: Next data
- *
- *     Update the FCS to include c. Uses the algorithm in the specification
- *     notes.
- */
-
-static inline u8 gsm_fcs_add(u8 fcs, u8 c)
-{
-       return gsm_fcs8[fcs ^ c];
-}
-
-/**
- *     gsm_fcs_add_block       -       update FCS for a block
- *     @fcs: Current FCS
- *     @c: buffer of data
- *     @len: length of buffer
- *
- *     Update the FCS to include c. Uses the algorithm in the specification
- *     notes.
- */
-
-static inline u8 gsm_fcs_add_block(u8 fcs, u8 *c, int len)
-{
-       while (len--)
-               fcs = gsm_fcs8[fcs ^ *c++];
-       return fcs;
-}
-
-/**
- *     gsm_read_ea             -       read a byte into an EA
- *     @val: variable holding value
- *     c: byte going into the EA
- *
- *     Processes one byte of an EA. Updates the passed variable
- *     and returns 1 if the EA is now completely read
- */
-
-static int gsm_read_ea(unsigned int *val, u8 c)
-{
-       /* Add the next 7 bits into the value */
-       *val <<= 7;
-       *val |= c >> 1;
-       /* Was this the last byte of the EA 1 = yes*/
-       return c & EA;
-}
-
-/**
- *     gsm_encode_modem        -       encode modem data bits
- *     @dlci: DLCI to encode from
- *
- *     Returns the correct GSM encoded modem status bits (6 bit field) for
- *     the current status of the DLCI and attached tty object
- */
-
-static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
-{
-       u8 modembits = 0;
-       /* FC is true flow control not modem bits */
-       if (dlci->throttled)
-               modembits |= MDM_FC;
-       if (dlci->modem_tx & TIOCM_DTR)
-               modembits |= MDM_RTC;
-       if (dlci->modem_tx & TIOCM_RTS)
-               modembits |= MDM_RTR;
-       if (dlci->modem_tx & TIOCM_RI)
-               modembits |= MDM_IC;
-       if (dlci->modem_tx & TIOCM_CD)
-               modembits |= MDM_DV;
-       return modembits;
-}
-
-/**
- *     gsm_print_packet        -       display a frame for debug
- *     @hdr: header to print before decode
- *     @addr: address EA from the frame
- *     @cr: C/R bit from the frame
- *     @control: control including PF bit
- *     @data: following data bytes
- *     @dlen: length of data
- *
- *     Displays a packet in human readable format for debugging purposes. The
- *     style is based on amateur radio LAP-B dump display.
- */
-
-static void gsm_print_packet(const char *hdr, int addr, int cr,
-                                       u8 control, const u8 *data, int dlen)
-{
-       if (!(debug & 1))
-               return;
-
-       printk(KERN_INFO "%s %d) %c: ", hdr, addr, "RC"[cr]);
-
-       switch (control & ~PF) {
-       case SABM:
-               printk(KERN_CONT "SABM");
-               break;
-       case UA:
-               printk(KERN_CONT "UA");
-               break;
-       case DISC:
-               printk(KERN_CONT "DISC");
-               break;
-       case DM:
-               printk(KERN_CONT "DM");
-               break;
-       case UI:
-               printk(KERN_CONT "UI");
-               break;
-       case UIH:
-               printk(KERN_CONT "UIH");
-               break;
-       default:
-               if (!(control & 0x01)) {
-                       printk(KERN_CONT "I N(S)%d N(R)%d",
-                               (control & 0x0E) >> 1, (control & 0xE)>> 5);
-               } else switch (control & 0x0F) {
-               case RR:
-                       printk("RR(%d)", (control & 0xE0) >> 5);
-                       break;
-               case RNR:
-                       printk("RNR(%d)", (control & 0xE0) >> 5);
-                       break;
-               case REJ:
-                       printk("REJ(%d)", (control & 0xE0) >> 5);
-                       break;
-               default:
-                       printk(KERN_CONT "[%02X]", control);
-               }
-       }
-
-       if (control & PF)
-               printk(KERN_CONT "(P)");
-       else
-               printk(KERN_CONT "(F)");
-
-       if (dlen) {
-               int ct = 0;
-               while (dlen--) {
-                       if (ct % 8 == 0)
-                               printk(KERN_CONT "\n    ");
-                       printk(KERN_CONT "%02X ", *data++);
-                       ct++;
-               }
-       }
-       printk(KERN_CONT "\n");
-}
-
-
-/*
- *     Link level transmission side
- */
-
-/**
- *     gsm_stuff_packet        -       bytestuff a packet
- *     @ibuf: input
- *     @obuf: output
- *     @len: length of input
- *
- *     Expand a buffer by bytestuffing it. The worst case size change
- *     is doubling and the caller is responsible for handing out
- *     suitable sized buffers.
- */
-
-static int gsm_stuff_frame(const u8 *input, u8 *output, int len)
-{
-       int olen = 0;
-       while (len--) {
-               if (*input == GSM1_SOF || *input == GSM1_ESCAPE
-                   || *input == XON || *input == XOFF) {
-                       *output++ = GSM1_ESCAPE;
-                       *output++ = *input++ ^ GSM1_ESCAPE_BITS;
-                       olen++;
-               } else
-                       *output++ = *input++;
-               olen++;
-       }
-       return olen;
-}
-
-static void hex_packet(const unsigned char *p, int len)
-{
-       int i;
-       for (i = 0; i < len; i++) {
-               if (i && (i % 16) == 0)
-                       printk("\n");
-               printk("%02X ", *p++);
-       }
-       printk("\n");
-}
-
-/**
- *     gsm_send        -       send a control frame
- *     @gsm: our GSM mux
- *     @addr: address for control frame
- *     @cr: command/response bit
- *     @control:  control byte including PF bit
- *
- *     Format up and transmit a control frame. These do not go via the
- *     queueing logic as they should be transmitted ahead of data when
- *     they are needed.
- *
- *     FIXME: Lock versus data TX path
- */
-
-static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
-{
-       int len;
-       u8 cbuf[10];
-       u8 ibuf[3];
-
-       switch (gsm->encoding) {
-       case 0:
-               cbuf[0] = GSM0_SOF;
-               cbuf[1] = (addr << 2) | (cr << 1) | EA;
-               cbuf[2] = control;
-               cbuf[3] = EA;   /* Length of data = 0 */
-               cbuf[4] = 0xFF - gsm_fcs_add_block(INIT_FCS, cbuf + 1, 3);
-               cbuf[5] = GSM0_SOF;
-               len = 6;
-               break;
-       case 1:
-       case 2:
-               /* Control frame + packing (but not frame stuffing) in mode 1 */
-               ibuf[0] = (addr << 2) | (cr << 1) | EA;
-               ibuf[1] = control;
-               ibuf[2] = 0xFF - gsm_fcs_add_block(INIT_FCS, ibuf, 2);
-               /* Stuffing may double the size worst case */
-               len = gsm_stuff_frame(ibuf, cbuf + 1, 3);
-               /* Now add the SOF markers */
-               cbuf[0] = GSM1_SOF;
-               cbuf[len + 1] = GSM1_SOF;
-               /* FIXME: we can omit the lead one in many cases */
-               len += 2;
-               break;
-       default:
-               WARN_ON(1);
-               return;
-       }
-       gsm->output(gsm, cbuf, len);
-       gsm_print_packet("-->", addr, cr, control, NULL, 0);
-}
-
-/**
- *     gsm_response    -       send a control response
- *     @gsm: our GSM mux
- *     @addr: address for control frame
- *     @control:  control byte including PF bit
- *
- *     Format up and transmit a link level response frame.
- */
-
-static inline void gsm_response(struct gsm_mux *gsm, int addr, int control)
-{
-       gsm_send(gsm, addr, 0, control);
-}
-
-/**
- *     gsm_command     -       send a control command
- *     @gsm: our GSM mux
- *     @addr: address for control frame
- *     @control:  control byte including PF bit
- *
- *     Format up and transmit a link level command frame.
- */
-
-static inline void gsm_command(struct gsm_mux *gsm, int addr, int control)
-{
-       gsm_send(gsm, addr, 1, control);
-}
-
-/* Data transmission */
-
-#define HDR_LEN                6       /* ADDR CTRL [LEN.2] DATA FCS */
-
-/**
- *     gsm_data_alloc          -       allocate data frame
- *     @gsm: GSM mux
- *     @addr: DLCI address
- *     @len: length excluding header and FCS
- *     @ctrl: control byte
- *
- *     Allocate a new data buffer for sending frames with data. Space is left
- *     at the front for header bytes but that is treated as an implementation
- *     detail and not for the high level code to use
- */
-
-static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
-                                                               u8 ctrl)
-{
-       struct gsm_msg *m = kmalloc(sizeof(struct gsm_msg) + len + HDR_LEN,
-                                                               GFP_ATOMIC);
-       if (m == NULL)
-               return NULL;
-       m->data = m->buffer + HDR_LEN - 1;      /* Allow for FCS */
-       m->len = len;
-       m->addr = addr;
-       m->ctrl = ctrl;
-       m->next = NULL;
-       return m;
-}
-
-/**
- *     gsm_data_kick           -       poke the queue
- *     @gsm: GSM Mux
- *
- *     The tty device has called us to indicate that room has appeared in
- *     the transmit queue. Ram more data into the pipe if we have any
- *
- *     FIXME: lock against link layer control transmissions
- */
-
-static void gsm_data_kick(struct gsm_mux *gsm)
-{
-       struct gsm_msg *msg = gsm->tx_head;
-       int len;
-       int skip_sof = 0;
-
-       /* FIXME: We need to apply this solely to data messages */
-       if (gsm->constipated)
-               return;
-
-       while (gsm->tx_head != NULL) {
-               msg = gsm->tx_head;
-               if (gsm->encoding != 0) {
-                       gsm->txframe[0] = GSM1_SOF;
-                       len = gsm_stuff_frame(msg->data,
-                                               gsm->txframe + 1, msg->len);
-                       gsm->txframe[len + 1] = GSM1_SOF;
-                       len += 2;
-               } else {
-                       gsm->txframe[0] = GSM0_SOF;
-                       memcpy(gsm->txframe + 1 , msg->data, msg->len);
-                       gsm->txframe[msg->len + 1] = GSM0_SOF;
-                       len = msg->len + 2;
-               }
-
-               if (debug & 4) {
-                       printk("gsm_data_kick: \n");
-                       hex_packet(gsm->txframe, len);
-               }
-
-               if (gsm->output(gsm, gsm->txframe + skip_sof,
-                                               len - skip_sof) < 0)
-                       break;
-               /* FIXME: Can eliminate one SOF in many more cases */
-               gsm->tx_head = msg->next;
-               if (gsm->tx_head == NULL)
-                       gsm->tx_tail = NULL;
-               gsm->tx_bytes -= msg->len;
-               kfree(msg);
-               /* For a burst of frames skip the extra SOF within the
-                  burst */
-               skip_sof = 1;
-       }
-}
-
-/**
- *     __gsm_data_queue                -       queue a UI or UIH frame
- *     @dlci: DLCI sending the data
- *     @msg: message queued
- *
- *     Add data to the transmit queue and try and get stuff moving
- *     out of the mux tty if not already doing so. The Caller must hold
- *     the gsm tx lock.
- */
-
-static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
-{
-       struct gsm_mux *gsm = dlci->gsm;
-       u8 *dp = msg->data;
-       u8 *fcs = dp + msg->len;
-
-       /* Fill in the header */
-       if (gsm->encoding == 0) {
-               if (msg->len < 128)
-                       *--dp = (msg->len << 1) | EA;
-               else {
-                       *--dp = (msg->len >> 6) | EA;
-                       *--dp = (msg->len & 127) << 1;
-               }
-       }
-
-       *--dp = msg->ctrl;
-       if (gsm->initiator)
-               *--dp = (msg->addr << 2) | 2 | EA;
-       else
-               *--dp = (msg->addr << 2) | EA;
-       *fcs = gsm_fcs_add_block(INIT_FCS, dp , msg->data - dp);
-       /* Ugly protocol layering violation */
-       if (msg->ctrl == UI || msg->ctrl == (UI|PF))
-               *fcs = gsm_fcs_add_block(*fcs, msg->data, msg->len);
-       *fcs = 0xFF - *fcs;
-
-       gsm_print_packet("Q> ", msg->addr, gsm->initiator, msg->ctrl,
-                                                       msg->data, msg->len);
-
-       /* Move the header back and adjust the length, also allow for the FCS
-          now tacked on the end */
-       msg->len += (msg->data - dp) + 1;
-       msg->data = dp;
-
-       /* Add to the actual output queue */
-       if (gsm->tx_tail)
-               gsm->tx_tail->next = msg;
-       else
-               gsm->tx_head = msg;
-       gsm->tx_tail = msg;
-       gsm->tx_bytes += msg->len;
-       gsm_data_kick(gsm);
-}
-
-/**
- *     gsm_data_queue          -       queue a UI or UIH frame
- *     @dlci: DLCI sending the data
- *     @msg: message queued
- *
- *     Add data to the transmit queue and try and get stuff moving
- *     out of the mux tty if not already doing so. Take the
- *     the gsm tx lock and dlci lock.
- */
-
-static void gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
-       __gsm_data_queue(dlci, msg);
-       spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
-}
-
-/**
- *     gsm_dlci_data_output    -       try and push data out of a DLCI
- *     @gsm: mux
- *     @dlci: the DLCI to pull data from
- *
- *     Pull data from a DLCI and send it into the transmit queue if there
- *     is data. Keep to the MRU of the mux. This path handles the usual tty
- *     interface which is a byte stream with optional modem data.
- *
- *     Caller must hold the tx_lock of the mux.
- */
-
-static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
-{
-       struct gsm_msg *msg;
-       u8 *dp;
-       int len, size;
-       int h = dlci->adaption - 1;
-
-       len = kfifo_len(dlci->fifo);
-       if (len == 0)
-               return 0;
-
-       /* MTU/MRU count only the data bits */
-       if (len > gsm->mtu)
-               len = gsm->mtu;
-
-       size = len + h;
-
-       msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
-       /* FIXME: need a timer or something to kick this so it can't
-          get stuck with no work outstanding and no buffer free */
-       if (msg == NULL)
-               return -ENOMEM;
-       dp = msg->data;
-       switch (dlci->adaption) {
-       case 1: /* Unstructured */
-               break;
-       case 2: /* Unstructed with modem bits. Always one byte as we never
-                  send inline break data */
-               *dp += gsm_encode_modem(dlci);
-               len--;
-               break;
-       }
-       WARN_ON(kfifo_out_locked(dlci->fifo, dp , len, &dlci->lock) != len);
-       __gsm_data_queue(dlci, msg);
-       /* Bytes of data we used up */
-       return size;
-}
-
-/**
- *     gsm_dlci_data_output_framed  -  try and push data out of a DLCI
- *     @gsm: mux
- *     @dlci: the DLCI to pull data from
- *
- *     Pull data from a DLCI and send it into the transmit queue if there
- *     is data. Keep to the MRU of the mux. This path handles framed data
- *     queued as skbuffs to the DLCI.
- *
- *     Caller must hold the tx_lock of the mux.
- */
-
-static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
-                                               struct gsm_dlci *dlci)
-{
-       struct gsm_msg *msg;
-       u8 *dp;
-       int len, size;
-       int last = 0, first = 0;
-       int overhead = 0;
-
-       /* One byte per frame is used for B/F flags */
-       if (dlci->adaption == 4)
-               overhead = 1;
-
-       /* dlci->skb is locked by tx_lock */
-       if (dlci->skb == NULL) {
-               dlci->skb = skb_dequeue(&dlci->skb_list);
-               if (dlci->skb == NULL)
-                       return 0;
-               first = 1;
-       }
-       len = dlci->skb->len + overhead;
-
-       /* MTU/MRU count only the data bits */
-       if (len > gsm->mtu) {
-               if (dlci->adaption == 3) {
-                       /* Over long frame, bin it */
-                       kfree_skb(dlci->skb);
-                       dlci->skb = NULL;
-                       return 0;
-               }
-               len = gsm->mtu;
-       } else
-               last = 1;
-
-       size = len + overhead;
-       msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
-
-       /* FIXME: need a timer or something to kick this so it can't
-          get stuck with no work outstanding and no buffer free */
-       if (msg == NULL)
-               return -ENOMEM;
-       dp = msg->data;
-
-       if (dlci->adaption == 4) { /* Interruptible framed (Packetised Data) */
-               /* Flag byte to carry the start/end info */
-               *dp++ = last << 7 | first << 6 | 1;     /* EA */
-               len--;
-       }
-       memcpy(dp, skb_pull(dlci->skb, len), len);
-       __gsm_data_queue(dlci, msg);
-       if (last)
-               dlci->skb = NULL;
-       return size;
-}
-
-/**
- *     gsm_dlci_data_sweep             -       look for data to send
- *     @gsm: the GSM mux
- *
- *     Sweep the GSM mux channels in priority order looking for ones with
- *     data to send. We could do with optimising this scan a bit. We aim
- *     to fill the queue totally or up to TX_THRESH_HI bytes. Once we hit
- *     TX_THRESH_LO we get called again
- *
- *     FIXME: We should round robin between groups and in theory you can
- *     renegotiate DLCI priorities with optional stuff. Needs optimising.
- */
-
-static void gsm_dlci_data_sweep(struct gsm_mux *gsm)
-{
-       int len;
-       /* Priority ordering: We should do priority with RR of the groups */
-       int i = 1;
-
-       while (i < NUM_DLCI) {
-               struct gsm_dlci *dlci;
-
-               if (gsm->tx_bytes > TX_THRESH_HI)
-                       break;
-               dlci = gsm->dlci[i];
-               if (dlci == NULL || dlci->constipated) {
-                       i++;
-                       continue;
-               }
-               if (dlci->adaption < 3)
-                       len = gsm_dlci_data_output(gsm, dlci);
-               else
-                       len = gsm_dlci_data_output_framed(gsm, dlci);
-               if (len < 0)
-                       break;
-               /* DLCI empty - try the next */
-               if (len == 0)
-                       i++;
-       }
-}
-
-/**
- *     gsm_dlci_data_kick      -       transmit if possible
- *     @dlci: DLCI to kick
- *
- *     Transmit data from this DLCI if the queue is empty. We can't rely on
- *     a tty wakeup except when we filled the pipe so we need to fire off
- *     new data ourselves in other cases.
- */
-
-static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
-       /* If we have nothing running then we need to fire up */
-       if (dlci->gsm->tx_bytes == 0)
-               gsm_dlci_data_output(dlci->gsm, dlci);
-       else if (dlci->gsm->tx_bytes < TX_THRESH_LO)
-               gsm_dlci_data_sweep(dlci->gsm);
-       spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
-}
-
-/*
- *     Control message processing
- */
-
-
-/**
- *     gsm_control_reply       -       send a response frame to a control
- *     @gsm: gsm channel
- *     @cmd: the command to use
- *     @data: data to follow encoded info
- *     @dlen: length of data
- *
- *     Encode up and queue a UI/UIH frame containing our response.
- */
-
-static void gsm_control_reply(struct gsm_mux *gsm, int cmd, u8 *data,
-                                       int dlen)
-{
-       struct gsm_msg *msg;
-       msg = gsm_data_alloc(gsm, 0, dlen + 2, gsm->ftype);
-       msg->data[0] = (cmd & 0xFE) << 1 | EA;  /* Clear C/R */
-       msg->data[1] = (dlen << 1) | EA;
-       memcpy(msg->data + 2, data, dlen);
-       gsm_data_queue(gsm->dlci[0], msg);
-}
-
-/**
- *     gsm_process_modem       -       process received modem status
- *     @tty: virtual tty bound to the DLCI
- *     @dlci: DLCI to affect
- *     @modem: modem bits (full EA)
- *
- *     Used when a modem control message or line state inline in adaption
- *     layer 2 is processed. Sort out the local modem state and throttles
- */
-
-static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
-                                                       u32 modem)
-{
-       int  mlines = 0;
-       u8 brk = modem >> 6;
-
-       /* Flow control/ready to communicate */
-       if (modem & MDM_FC) {
-               /* Need to throttle our output on this device */
-               dlci->constipated = 1;
-       }
-       if (modem & MDM_RTC) {
-               mlines |= TIOCM_DSR | TIOCM_DTR;
-               dlci->constipated = 0;
-               gsm_dlci_data_kick(dlci);
-       }
-       /* Map modem bits */
-       if (modem & MDM_RTR)
-               mlines |= TIOCM_RTS | TIOCM_CTS;
-       if (modem & MDM_IC)
-               mlines |= TIOCM_RI;
-       if (modem & MDM_DV)
-               mlines |= TIOCM_CD;
-
-       /* Carrier drop -> hangup */
-       if (tty) {
-               if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD))
-                       if (!(tty->termios->c_cflag & CLOCAL))
-                               tty_hangup(tty);
-               if (brk & 0x01)
-                       tty_insert_flip_char(tty, 0, TTY_BREAK);
-       }
-       dlci->modem_rx = mlines;
-}
-
-/**
- *     gsm_control_modem       -       modem status received
- *     @gsm: GSM channel
- *     @data: data following command
- *     @clen: command length
- *
- *     We have received a modem status control message. This is used by
- *     the GSM mux protocol to pass virtual modem line status and optionally
- *     to indicate break signals. Unpack it, convert to Linux representation
- *     and if need be stuff a break message down the tty.
- */
-
-static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
-{
-       unsigned int addr = 0;
-       unsigned int modem = 0;
-       struct gsm_dlci *dlci;
-       int len = clen;
-       u8 *dp = data;
-       struct tty_struct *tty;
-
-       while (gsm_read_ea(&addr, *dp++) == 0) {
-               len--;
-               if (len == 0)
-                       return;
-       }
-       /* Must be at least one byte following the EA */
-       len--;
-       if (len <= 0)
-               return;
-
-       addr >>= 1;
-       /* Closed port, or invalid ? */
-       if (addr == 0 || addr >= NUM_DLCI || gsm->dlci[addr] == NULL)
-               return;
-       dlci = gsm->dlci[addr];
-
-       while (gsm_read_ea(&modem, *dp++) == 0) {
-               len--;
-               if (len == 0)
-                       return;
-       }
-       tty = tty_port_tty_get(&dlci->port);
-       gsm_process_modem(tty, dlci, modem);
-       if (tty) {
-               tty_wakeup(tty);
-               tty_kref_put(tty);
-       }
-       gsm_control_reply(gsm, CMD_MSC, data, clen);
-}
-
-/**
- *     gsm_control_rls         -       remote line status
- *     @gsm: GSM channel
- *     @data: data bytes
- *     @clen: data length
- *
- *     The modem sends us a two byte message on the control channel whenever
- *     it wishes to send us an error state from the virtual link. Stuff
- *     this into the uplink tty if present
- */
-
-static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen)
-{
-       struct tty_struct *tty;
-       unsigned int addr = 0 ;
-       u8 bits;
-       int len = clen;
-       u8 *dp = data;
-
-       while (gsm_read_ea(&addr, *dp++) == 0) {
-               len--;
-               if (len == 0)
-                       return;
-       }
-       /* Must be at least one byte following ea */
-       len--;
-       if (len <= 0)
-               return;
-       addr >>= 1;
-       /* Closed port, or invalid ? */
-       if (addr == 0 || addr >= NUM_DLCI || gsm->dlci[addr] == NULL)
-               return;
-       /* No error ? */
-       bits = *dp;
-       if ((bits & 1) == 0)
-               return;
-       /* See if we have an uplink tty */
-       tty = tty_port_tty_get(&gsm->dlci[addr]->port);
-
-       if (tty) {
-               if (bits & 2)
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               if (bits & 4)
-                       tty_insert_flip_char(tty, 0, TTY_PARITY);
-               if (bits & 8)
-                       tty_insert_flip_char(tty, 0, TTY_FRAME);
-               tty_flip_buffer_push(tty);
-               tty_kref_put(tty);
-       }
-       gsm_control_reply(gsm, CMD_RLS, data, clen);
-}
-
-static void gsm_dlci_begin_close(struct gsm_dlci *dlci);
-
-/**
- *     gsm_control_message     -       DLCI 0 control processing
- *     @gsm: our GSM mux
- *     @command:  the command EA
- *     @data: data beyond the command/length EAs
- *     @clen: length
- *
- *     Input processor for control messages from the other end of the link.
- *     Processes the incoming request and queues a response frame or an
- *     NSC response if not supported
- */
-
-static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
-                                                       u8 *data, int clen)
-{
-       u8 buf[1];
-       switch (command) {
-       case CMD_CLD: {
-               struct gsm_dlci *dlci = gsm->dlci[0];
-               /* Modem wishes to close down */
-               if (dlci) {
-                       dlci->dead = 1;
-                       gsm->dead = 1;
-                       gsm_dlci_begin_close(dlci);
-               }
-               }
-               break;
-       case CMD_TEST:
-               /* Modem wishes to test, reply with the data */
-               gsm_control_reply(gsm, CMD_TEST, data, clen);
-               break;
-       case CMD_FCON:
-               /* Modem wants us to STFU */
-               gsm->constipated = 1;
-               gsm_control_reply(gsm, CMD_FCON, NULL, 0);
-               break;
-       case CMD_FCOFF:
-               /* Modem can accept data again */
-               gsm->constipated = 0;
-               gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
-               /* Kick the link in case it is idling */
-               gsm_data_kick(gsm);
-               break;
-       case CMD_MSC:
-               /* Out of band modem line change indicator for a DLCI */
-               gsm_control_modem(gsm, data, clen);
-               break;
-       case CMD_RLS:
-               /* Out of band error reception for a DLCI */
-               gsm_control_rls(gsm, data, clen);
-               break;
-       case CMD_PSC:
-               /* Modem wishes to enter power saving state */
-               gsm_control_reply(gsm, CMD_PSC, NULL, 0);
-               break;
-               /* Optional unsupported commands */
-       case CMD_PN:    /* Parameter negotiation */
-       case CMD_RPN:   /* Remote port negotation */
-       case CMD_SNC:   /* Service negotation command */
-       default:
-               /* Reply to bad commands with an NSC */
-               buf[0] = command;
-               gsm_control_reply(gsm, CMD_NSC, buf, 1);
-               break;
-       }
-}
-
-/**
- *     gsm_control_response    -       process a response to our control
- *     @gsm: our GSM mux
- *     @command: the command (response) EA
- *     @data: data beyond the command/length EA
- *     @clen: length
- *
- *     Process a response to an outstanding command. We only allow a single
- *     control message in flight so this is fairly easy. All the clean up
- *     is done by the caller, we just update the fields, flag it as done
- *     and return
- */
-
-static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
-                                                       u8 *data, int clen)
-{
-       struct gsm_control *ctrl;
-       unsigned long flags;
-
-       spin_lock_irqsave(&gsm->control_lock, flags);
-
-       ctrl = gsm->pending_cmd;
-       /* Does the reply match our command */
-       command |= 1;
-       if (ctrl != NULL && (command == ctrl->cmd || command == CMD_NSC)) {
-               /* Our command was replied to, kill the retry timer */
-               del_timer(&gsm->t2_timer);
-               gsm->pending_cmd = NULL;
-               /* Rejected by the other end */
-               if (command == CMD_NSC)
-                       ctrl->error = -EOPNOTSUPP;
-               ctrl->done = 1;
-               wake_up(&gsm->event);
-       }
-       spin_unlock_irqrestore(&gsm->control_lock, flags);
-}
-
-/**
- *     gsm_control_transmit    -       send control packet
- *     @gsm: gsm mux
- *     @ctrl: frame to send
- *
- *     Send out a pending control command (called under control lock)
- */
-
-static void gsm_control_transmit(struct gsm_mux *gsm, struct gsm_control *ctrl)
-{
-       struct gsm_msg *msg = gsm_data_alloc(gsm, 0, ctrl->len + 1,
-                                                       gsm->ftype|PF);
-       if (msg == NULL)
-               return;
-       msg->data[0] = (ctrl->cmd << 1) | 2 | EA;       /* command */
-       memcpy(msg->data + 1, ctrl->data, ctrl->len);
-       gsm_data_queue(gsm->dlci[0], msg);
-}
-
-/**
- *     gsm_control_retransmit  -       retransmit a control frame
- *     @data: pointer to our gsm object
- *
- *     Called off the T2 timer expiry in order to retransmit control frames
- *     that have been lost in the system somewhere. The control_lock protects
- *     us from colliding with another sender or a receive completion event.
- *     In that situation the timer may still occur in a small window but
- *     gsm->pending_cmd will be NULL and we just let the timer expire.
- */
-
-static void gsm_control_retransmit(unsigned long data)
-{
-       struct gsm_mux *gsm = (struct gsm_mux *)data;
-       struct gsm_control *ctrl;
-       unsigned long flags;
-       spin_lock_irqsave(&gsm->control_lock, flags);
-       ctrl = gsm->pending_cmd;
-       if (ctrl) {
-               gsm->cretries--;
-               if (gsm->cretries == 0) {
-                       gsm->pending_cmd = NULL;
-                       ctrl->error = -ETIMEDOUT;
-                       ctrl->done = 1;
-                       spin_unlock_irqrestore(&gsm->control_lock, flags);
-                       wake_up(&gsm->event);
-                       return;
-               }
-               gsm_control_transmit(gsm, ctrl);
-               mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
-       }
-       spin_unlock_irqrestore(&gsm->control_lock, flags);
-}
-
-/**
- *     gsm_control_send        -       send a control frame on DLCI 0
- *     @gsm: the GSM channel
- *     @command: command  to send including CR bit
- *     @data: bytes of data (must be kmalloced)
- *     @len: length of the block to send
- *
- *     Queue and dispatch a control command. Only one command can be
- *     active at a time. In theory more can be outstanding but the matching
- *     gets really complicated so for now stick to one outstanding.
- */
-
-static struct gsm_control *gsm_control_send(struct gsm_mux *gsm,
-               unsigned int command, u8 *data, int clen)
-{
-       struct gsm_control *ctrl = kzalloc(sizeof(struct gsm_control),
-                                               GFP_KERNEL);
-       unsigned long flags;
-       if (ctrl == NULL)
-               return NULL;
-retry:
-       wait_event(gsm->event, gsm->pending_cmd == NULL);
-       spin_lock_irqsave(&gsm->control_lock, flags);
-       if (gsm->pending_cmd != NULL) {
-               spin_unlock_irqrestore(&gsm->control_lock, flags);
-               goto retry;
-       }
-       ctrl->cmd = command;
-       ctrl->data = data;
-       ctrl->len = clen;
-       gsm->pending_cmd = ctrl;
-       gsm->cretries = gsm->n2;
-       mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
-       gsm_control_transmit(gsm, ctrl);
-       spin_unlock_irqrestore(&gsm->control_lock, flags);
-       return ctrl;
-}
-
-/**
- *     gsm_control_wait        -       wait for a control to finish
- *     @gsm: GSM mux
- *     @control: control we are waiting on
- *
- *     Waits for the control to complete or time out. Frees any used
- *     resources and returns 0 for success, or an error if the remote
- *     rejected or ignored the request.
- */
-
-static int gsm_control_wait(struct gsm_mux *gsm, struct gsm_control *control)
-{
-       int err;
-       wait_event(gsm->event, control->done == 1);
-       err = control->error;
-       kfree(control);
-       return err;
-}
-
-
-/*
- *     DLCI level handling: Needs krefs
- */
-
-/*
- *     State transitions and timers
- */
-
-/**
- *     gsm_dlci_close          -       a DLCI has closed
- *     @dlci: DLCI that closed
- *
- *     Perform processing when moving a DLCI into closed state. If there
- *     is an attached tty this is hung up
- */
-
-static void gsm_dlci_close(struct gsm_dlci *dlci)
-{
-       del_timer(&dlci->t1);
-       if (debug & 8)
-               printk("DLCI %d goes closed.\n", dlci->addr);
-       dlci->state = DLCI_CLOSED;
-       if (dlci->addr != 0) {
-               struct tty_struct  *tty = tty_port_tty_get(&dlci->port);
-               if (tty) {
-                       tty_hangup(tty);
-                       tty_kref_put(tty);
-               }
-               kfifo_reset(dlci->fifo);
-       } else
-               dlci->gsm->dead = 1;
-       wake_up(&dlci->gsm->event);
-       /* A DLCI 0 close is a MUX termination so we need to kick that
-          back to userspace somehow */
-}
-
-/**
- *     gsm_dlci_open           -       a DLCI has opened
- *     @dlci: DLCI that opened
- *
- *     Perform processing when moving a DLCI into open state.
- */
-
-static void gsm_dlci_open(struct gsm_dlci *dlci)
-{
-       /* Note that SABM UA .. SABM UA first UA lost can mean that we go
-          open -> open */
-       del_timer(&dlci->t1);
-       /* This will let a tty open continue */
-       dlci->state = DLCI_OPEN;
-       if (debug & 8)
-               printk("DLCI %d goes open.\n", dlci->addr);
-       wake_up(&dlci->gsm->event);
-}
-
-/**
- *     gsm_dlci_t1             -       T1 timer expiry
- *     @dlci: DLCI that opened
- *
- *     The T1 timer handles retransmits of control frames (essentially of
- *     SABM and DISC). We resend the command until the retry count runs out
- *     in which case an opening port goes back to closed and a closing port
- *     is simply put into closed state (any further frames from the other
- *     end will get a DM response)
- */
-
-static void gsm_dlci_t1(unsigned long data)
-{
-       struct gsm_dlci *dlci = (struct gsm_dlci *)data;
-       struct gsm_mux *gsm = dlci->gsm;
-
-       switch (dlci->state) {
-       case DLCI_OPENING:
-               dlci->retries--;
-               if (dlci->retries) {
-                       gsm_command(dlci->gsm, dlci->addr, SABM|PF);
-                       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
-               } else
-                       gsm_dlci_close(dlci);
-               break;
-       case DLCI_CLOSING:
-               dlci->retries--;
-               if (dlci->retries) {
-                       gsm_command(dlci->gsm, dlci->addr, DISC|PF);
-                       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
-               } else
-                       gsm_dlci_close(dlci);
-               break;
-       }
-}
-
-/**
- *     gsm_dlci_begin_open     -       start channel open procedure
- *     @dlci: DLCI to open
- *
- *     Commence opening a DLCI from the Linux side. We issue SABM messages
- *     to the modem which should then reply with a UA, at which point we
- *     will move into open state. Opening is done asynchronously with retry
- *     running off timers and the responses.
- */
-
-static void gsm_dlci_begin_open(struct gsm_dlci *dlci)
-{
-       struct gsm_mux *gsm = dlci->gsm;
-       if (dlci->state == DLCI_OPEN || dlci->state == DLCI_OPENING)
-               return;
-       dlci->retries = gsm->n2;
-       dlci->state = DLCI_OPENING;
-       gsm_command(dlci->gsm, dlci->addr, SABM|PF);
-       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
-}
-
-/**
- *     gsm_dlci_begin_close    -       start channel open procedure
- *     @dlci: DLCI to open
- *
- *     Commence closing a DLCI from the Linux side. We issue DISC messages
- *     to the modem which should then reply with a UA, at which point we
- *     will move into closed state. Closing is done asynchronously with retry
- *     off timers. We may also receive a DM reply from the other end which
- *     indicates the channel was already closed.
- */
-
-static void gsm_dlci_begin_close(struct gsm_dlci *dlci)
-{
-       struct gsm_mux *gsm = dlci->gsm;
-       if (dlci->state == DLCI_CLOSED || dlci->state == DLCI_CLOSING)
-               return;
-       dlci->retries = gsm->n2;
-       dlci->state = DLCI_CLOSING;
-       gsm_command(dlci->gsm, dlci->addr, DISC|PF);
-       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
-}
-
-/**
- *     gsm_dlci_data           -       data arrived
- *     @dlci: channel
- *     @data: block of bytes received
- *     @len: length of received block
- *
- *     A UI or UIH frame has arrived which contains data for a channel
- *     other than the control channel. If the relevant virtual tty is
- *     open we shovel the bits down it, if not we drop them.
- */
-
-static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int len)
-{
-       /* krefs .. */
-       struct tty_port *port = &dlci->port;
-       struct tty_struct *tty = tty_port_tty_get(port);
-       unsigned int modem = 0;
-
-       if (debug & 16)
-               printk("%d bytes for tty %p\n", len, tty);
-       if (tty) {
-               switch (dlci->adaption)  {
-                       /* Unsupported types */
-                       /* Packetised interruptible data */
-                       case 4:
-                               break;
-                       /* Packetised uininterruptible voice/data */
-                       case 3:
-                               break;
-                       /* Asynchronous serial with line state in each frame */
-                       case 2:
-                               while (gsm_read_ea(&modem, *data++) == 0) {
-                                       len--;
-                                       if (len == 0)
-                                               return;
-                               }
-                               gsm_process_modem(tty, dlci, modem);
-                       /* Line state will go via DLCI 0 controls only */
-                       case 1:
-                       default:
-                               tty_insert_flip_string(tty, data, len);
-                               tty_flip_buffer_push(tty);
-               }
-               tty_kref_put(tty);
-       }
-}
-
-/**
- *     gsm_dlci_control        -       data arrived on control channel
- *     @dlci: channel
- *     @data: block of bytes received
- *     @len: length of received block
- *
- *     A UI or UIH frame has arrived which contains data for DLCI 0 the
- *     control channel. This should contain a command EA followed by
- *     control data bytes. The command EA contains a command/response bit
- *     and we divide up the work accordingly.
- */
-
-static void gsm_dlci_command(struct gsm_dlci *dlci, u8 *data, int len)
-{
-       /* See what command is involved */
-       unsigned int command = 0;
-       while (len-- > 0) {
-               if (gsm_read_ea(&command, *data++) == 1) {
-                       int clen = *data++;
-                       len--;
-                       /* FIXME: this is properly an EA */
-                       clen >>= 1;
-                       /* Malformed command ? */
-                       if (clen > len)
-                               return;
-                       if (command & 1)
-                               gsm_control_message(dlci->gsm, command,
-                                                               data, clen);
-                       else
-                               gsm_control_response(dlci->gsm, command,
-                                                               data, clen);
-                       return;
-               }
-       }
-}
-
-/*
- *     Allocate/Free DLCI channels
- */
-
-/**
- *     gsm_dlci_alloc          -       allocate a DLCI
- *     @gsm: GSM mux
- *     @addr: address of the DLCI
- *
- *     Allocate and install a new DLCI object into the GSM mux.
- *
- *     FIXME: review locking races
- */
-
-static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
-{
-       struct gsm_dlci *dlci = kzalloc(sizeof(struct gsm_dlci), GFP_ATOMIC);
-       if (dlci == NULL)
-               return NULL;
-       spin_lock_init(&dlci->lock);
-       dlci->fifo = &dlci->_fifo;
-       if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) {
-               kfree(dlci);
-               return NULL;
-       }
-
-       skb_queue_head_init(&dlci->skb_list);
-       init_timer(&dlci->t1);
-       dlci->t1.function = gsm_dlci_t1;
-       dlci->t1.data = (unsigned long)dlci;
-       tty_port_init(&dlci->port);
-       dlci->port.ops = &gsm_port_ops;
-       dlci->gsm = gsm;
-       dlci->addr = addr;
-       dlci->adaption = gsm->adaption;
-       dlci->state = DLCI_CLOSED;
-       if (addr)
-               dlci->data = gsm_dlci_data;
-       else
-               dlci->data = gsm_dlci_command;
-       gsm->dlci[addr] = dlci;
-       return dlci;
-}
-
-/**
- *     gsm_dlci_free           -       release DLCI
- *     @dlci: DLCI to destroy
- *
- *     Free up a DLCI. Currently to keep the lifetime rules sane we only
- *     clean up DLCI objects when the MUX closes rather than as the port
- *     is closed down on both the tty and mux levels.
- *
- *     Can sleep.
- */
-static void gsm_dlci_free(struct gsm_dlci *dlci)
-{
-       struct tty_struct *tty = tty_port_tty_get(&dlci->port);
-       if (tty) {
-               tty_vhangup(tty);
-               tty_kref_put(tty);
-       }
-       del_timer_sync(&dlci->t1);
-       dlci->gsm->dlci[dlci->addr] = NULL;
-       kfifo_free(dlci->fifo);
-       kfree(dlci);
-}
-
-
-/*
- *     LAPBish link layer logic
- */
-
-/**
- *     gsm_queue               -       a GSM frame is ready to process
- *     @gsm: pointer to our gsm mux
- *
- *     At this point in time a frame has arrived and been demangled from
- *     the line encoding. All the differences between the encodings have
- *     been handled below us and the frame is unpacked into the structures.
- *     The fcs holds the header FCS but any data FCS must be added here.
- */
-
-static void gsm_queue(struct gsm_mux *gsm)
-{
-       struct gsm_dlci *dlci;
-       u8 cr;
-       int address;
-       /* We have to sneak a look at the packet body to do the FCS.
-          A somewhat layering violation in the spec */
-
-       if ((gsm->control & ~PF) == UI)
-               gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len);
-       if (gsm->fcs != GOOD_FCS) {
-               gsm->bad_fcs++;
-               if (debug & 4)
-                       printk("BAD FCS %02x\n", gsm->fcs);
-               return;
-       }
-       address = gsm->address >> 1;
-       if (address >= NUM_DLCI)
-               goto invalid;
-
-       cr = gsm->address & 1;          /* C/R bit */
-
-       gsm_print_packet("<--", address, cr, gsm->control, gsm->buf, gsm->len);
-
-       cr ^= 1 - gsm->initiator;       /* Flip so 1 always means command */
-       dlci = gsm->dlci[address];
-
-       switch (gsm->control) {
-       case SABM|PF:
-               if (cr == 0)
-                       goto invalid;
-               if (dlci == NULL)
-                       dlci = gsm_dlci_alloc(gsm, address);
-               if (dlci == NULL)
-                       return;
-               if (dlci->dead)
-                       gsm_response(gsm, address, DM);
-               else {
-                       gsm_response(gsm, address, UA);
-                       gsm_dlci_open(dlci);
-               }
-               break;
-       case DISC|PF:
-               if (cr == 0)
-                       goto invalid;
-               if (dlci == NULL || dlci->state == DLCI_CLOSED) {
-                       gsm_response(gsm, address, DM);
-                       return;
-               }
-               /* Real close complete */
-               gsm_response(gsm, address, UA);
-               gsm_dlci_close(dlci);
-               break;
-       case UA:
-       case UA|PF:
-               if (cr == 0 || dlci == NULL)
-                       break;
-               switch (dlci->state) {
-               case DLCI_CLOSING:
-                       gsm_dlci_close(dlci);
-                       break;
-               case DLCI_OPENING:
-                       gsm_dlci_open(dlci);
-                       break;
-               }
-               break;
-       case DM:        /* DM can be valid unsolicited */
-       case DM|PF:
-               if (cr)
-                       goto invalid;
-               if (dlci == NULL)
-                       return;
-               gsm_dlci_close(dlci);
-               break;
-       case UI:
-       case UI|PF:
-       case UIH:
-       case UIH|PF:
-#if 0
-               if (cr)
-                       goto invalid;
-#endif
-               if (dlci == NULL || dlci->state != DLCI_OPEN) {
-                       gsm_command(gsm, address, DM|PF);
-                       return;
-               }
-               dlci->data(dlci, gsm->buf, gsm->len);
-               break;
-       default:
-               goto invalid;
-       }
-       return;
-invalid:
-       gsm->malformed++;
-       return;
-}
-
-
-/**
- *     gsm0_receive    -       perform processing for non-transparency
- *     @gsm: gsm data for this ldisc instance
- *     @c: character
- *
- *     Receive bytes in gsm mode 0
- */
-
-static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
-{
-       switch (gsm->state) {
-       case GSM_SEARCH:        /* SOF marker */
-               if (c == GSM0_SOF) {
-                       gsm->state = GSM_ADDRESS;
-                       gsm->address = 0;
-                       gsm->len = 0;
-                       gsm->fcs = INIT_FCS;
-               }
-               break;          /* Address EA */
-       case GSM_ADDRESS:
-               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-               if (gsm_read_ea(&gsm->address, c))
-                       gsm->state = GSM_CONTROL;
-               break;
-       case GSM_CONTROL:       /* Control Byte */
-               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-               gsm->control = c;
-               gsm->state = GSM_LEN;
-               break;
-       case GSM_LEN:           /* Length EA */
-               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-               if (gsm_read_ea(&gsm->len, c)) {
-                       if (gsm->len > gsm->mru) {
-                               gsm->bad_size++;
-                               gsm->state = GSM_SEARCH;
-                               break;
-                       }
-                       gsm->count = 0;
-                       gsm->state = GSM_DATA;
-               }
-               break;
-       case GSM_DATA:          /* Data */
-               gsm->buf[gsm->count++] = c;
-               if (gsm->count == gsm->len)
-                       gsm->state = GSM_FCS;
-               break;
-       case GSM_FCS:           /* FCS follows the packet */
-               gsm->fcs = c;
-               gsm_queue(gsm);
-               /* And then back for the next frame */
-               gsm->state = GSM_SEARCH;
-               break;
-       }
-}
-
-/**
- *     gsm0_receive    -       perform processing for non-transparency
- *     @gsm: gsm data for this ldisc instance
- *     @c: character
- *
- *     Receive bytes in mode 1 (Advanced option)
- */
-
-static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
-{
-       if (c == GSM1_SOF) {
-               /* EOF is only valid in frame if we have got to the data state
-                  and received at least one byte (the FCS) */
-               if (gsm->state == GSM_DATA && gsm->count) {
-                       /* Extract the FCS */
-                       gsm->count--;
-                       gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->buf[gsm->count]);
-                       gsm->len = gsm->count;
-                       gsm_queue(gsm);
-                       gsm->state  = GSM_START;
-                       return;
-               }
-               /* Any partial frame was a runt so go back to start */
-               if (gsm->state != GSM_START) {
-                       gsm->malformed++;
-                       gsm->state = GSM_START;
-               }
-               /* A SOF in GSM_START means we are still reading idling or
-                  framing bytes */
-               return;
-       }
-
-       if (c == GSM1_ESCAPE) {
-               gsm->escape = 1;
-               return;
-       }
-
-       /* Only an unescaped SOF gets us out of GSM search */
-       if (gsm->state == GSM_SEARCH)
-               return;
-
-       if (gsm->escape) {
-               c ^= GSM1_ESCAPE_BITS;
-               gsm->escape = 0;
-       }
-       switch (gsm->state) {
-       case GSM_START:         /* First byte after SOF */
-               gsm->address = 0;
-               gsm->state = GSM_ADDRESS;
-               gsm->fcs = INIT_FCS;
-               /* Drop through */
-       case GSM_ADDRESS:       /* Address continuation */
-               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-               if (gsm_read_ea(&gsm->address, c))
-                       gsm->state = GSM_CONTROL;
-               break;
-       case GSM_CONTROL:       /* Control Byte */
-               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
-               gsm->control = c;
-               gsm->count = 0;
-               gsm->state = GSM_DATA;
-               break;
-       case GSM_DATA:          /* Data */
-               if (gsm->count > gsm->mru ) {   /* Allow one for the FCS */
-                       gsm->state = GSM_OVERRUN;
-                       gsm->bad_size++;
-               } else
-                       gsm->buf[gsm->count++] = c;
-               break;
-       case GSM_OVERRUN:       /* Over-long - eg a dropped SOF */
-               break;
-       }
-}
-
-/**
- *     gsm_error               -       handle tty error
- *     @gsm: ldisc data
- *     @data: byte received (may be invalid)
- *     @flag: error received
- *
- *     Handle an error in the receipt of data for a frame. Currently we just
- *     go back to hunting for a SOF.
- *
- *     FIXME: better diagnostics ?
- */
-
-static void gsm_error(struct gsm_mux *gsm,
-                               unsigned char data, unsigned char flag)
-{
-       gsm->state = GSM_SEARCH;
-       gsm->io_error++;
-}
-
-/**
- *     gsm_cleanup_mux         -       generic GSM protocol cleanup
- *     @gsm: our mux
- *
- *     Clean up the bits of the mux which are the same for all framing
- *     protocols. Remove the mux from the mux table, stop all the timers
- *     and then shut down each device hanging up the channels as we go.
- */
-
-void gsm_cleanup_mux(struct gsm_mux *gsm)
-{
-       int i;
-       struct gsm_dlci *dlci = gsm->dlci[0];
-       struct gsm_msg *txq;
-
-       gsm->dead = 1;
-
-       spin_lock(&gsm_mux_lock);
-       for (i = 0; i < MAX_MUX; i++) {
-               if (gsm_mux[i] == gsm) {
-                       gsm_mux[i] = NULL;
-                       break;
-               }
-       }
-       spin_unlock(&gsm_mux_lock);
-       WARN_ON(i == MAX_MUX);
-
-       del_timer_sync(&gsm->t2_timer);
-       /* Now we are sure T2 has stopped */
-       if (dlci) {
-               dlci->dead = 1;
-               gsm_dlci_begin_close(dlci);
-               wait_event_interruptible(gsm->event,
-                                       dlci->state == DLCI_CLOSED);
-       }
-       /* Free up any link layer users */
-       for (i = 0; i < NUM_DLCI; i++)
-               if (gsm->dlci[i])
-                       gsm_dlci_free(gsm->dlci[i]);
-       /* Now wipe the queues */
-       for (txq = gsm->tx_head; txq != NULL; txq = gsm->tx_head) {
-               gsm->tx_head = txq->next;
-               kfree(txq);
-       }
-       gsm->tx_tail = NULL;
-}
-EXPORT_SYMBOL_GPL(gsm_cleanup_mux);
-
-/**
- *     gsm_activate_mux        -       generic GSM setup
- *     @gsm: our mux
- *
- *     Set up the bits of the mux which are the same for all framing
- *     protocols. Add the mux to the mux table so it can be opened and
- *     finally kick off connecting to DLCI 0 on the modem.
- */
-
-int gsm_activate_mux(struct gsm_mux *gsm)
-{
-       struct gsm_dlci *dlci;
-       int i = 0;
-
-       init_timer(&gsm->t2_timer);
-       gsm->t2_timer.function = gsm_control_retransmit;
-       gsm->t2_timer.data = (unsigned long)gsm;
-       init_waitqueue_head(&gsm->event);
-       spin_lock_init(&gsm->control_lock);
-       spin_lock_init(&gsm->tx_lock);
-
-       if (gsm->encoding == 0)
-               gsm->receive = gsm0_receive;
-       else
-               gsm->receive = gsm1_receive;
-       gsm->error = gsm_error;
-
-       spin_lock(&gsm_mux_lock);
-       for (i = 0; i < MAX_MUX; i++) {
-               if (gsm_mux[i] == NULL) {
-                       gsm_mux[i] = gsm;
-                       break;
-               }
-       }
-       spin_unlock(&gsm_mux_lock);
-       if (i == MAX_MUX)
-               return -EBUSY;
-
-       dlci = gsm_dlci_alloc(gsm, 0);
-       if (dlci == NULL)
-               return -ENOMEM;
-       gsm->dead = 0;          /* Tty opens are now permissible */
-       return 0;
-}
-EXPORT_SYMBOL_GPL(gsm_activate_mux);
-
-/**
- *     gsm_free_mux            -       free up a mux
- *     @mux: mux to free
- *
- *     Dispose of allocated resources for a dead mux. No refcounting
- *     at present so the mux must be truely dead.
- */
-void gsm_free_mux(struct gsm_mux *gsm)
-{
-       kfree(gsm->txframe);
-       kfree(gsm->buf);
-       kfree(gsm);
-}
-EXPORT_SYMBOL_GPL(gsm_free_mux);
-
-/**
- *     gsm_alloc_mux           -       allocate a mux
- *
- *     Creates a new mux ready for activation.
- */
-
-struct gsm_mux *gsm_alloc_mux(void)
-{
-       struct gsm_mux *gsm = kzalloc(sizeof(struct gsm_mux), GFP_KERNEL);
-       if (gsm == NULL)
-               return NULL;
-       gsm->buf = kmalloc(MAX_MRU + 1, GFP_KERNEL);
-       if (gsm->buf == NULL) {
-               kfree(gsm);
-               return NULL;
-       }
-       gsm->txframe = kmalloc(2 * MAX_MRU + 2, GFP_KERNEL);
-       if (gsm->txframe == NULL) {
-               kfree(gsm->buf);
-               kfree(gsm);
-               return NULL;
-       }
-       spin_lock_init(&gsm->lock);
-
-       gsm->t1 = T1;
-       gsm->t2 = T2;
-       gsm->n2 = N2;
-       gsm->ftype = UIH;
-       gsm->initiator = 0;
-       gsm->adaption = 1;
-       gsm->encoding = 1;
-       gsm->mru = 64;  /* Default to encoding 1 so these should be 64 */
-       gsm->mtu = 64;
-       gsm->dead = 1;  /* Avoid early tty opens */
-
-       return gsm;
-}
-EXPORT_SYMBOL_GPL(gsm_alloc_mux);
-
-
-
-
-/**
- *     gsmld_output            -       write to link
- *     @gsm: our mux
- *     @data: bytes to output
- *     @len: size
- *
- *     Write a block of data from the GSM mux to the data channel. This
- *     will eventually be serialized from above but at the moment isn't.
- */
-
-static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len)
-{
-       if (tty_write_room(gsm->tty) < len) {
-               set_bit(TTY_DO_WRITE_WAKEUP, &gsm->tty->flags);
-               return -ENOSPC;
-       }
-       if (debug & 4) {
-               printk("-->%d bytes out\n", len);
-               hex_packet(data, len);
-       }
-       gsm->tty->ops->write(gsm->tty, data, len);
-       return len;
-}
-
-/**
- *     gsmld_attach_gsm        -       mode set up
- *     @tty: our tty structure
- *     @gsm: our mux
- *
- *     Set up the MUX for basic mode and commence connecting to the
- *     modem. Currently called from the line discipline set up but
- *     will need moving to an ioctl path.
- */
-
-static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
-{
-       int ret;
-
-       gsm->tty = tty_kref_get(tty);
-       gsm->output = gsmld_output;
-       ret =  gsm_activate_mux(gsm);
-       if (ret != 0)
-               tty_kref_put(gsm->tty);
-       return ret;
-}
-
-
-/**
- *     gsmld_detach_gsm        -       stop doing 0710 mux
- *     @tty: tty atttached to the mux
- *     @gsm: mux
- *
- *     Shutdown and then clean up the resources used by the line discipline
- */
-
-static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
-{
-       WARN_ON(tty != gsm->tty);
-       gsm_cleanup_mux(gsm);
-       tty_kref_put(gsm->tty);
-       gsm->tty = NULL;
-}
-
-static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-                             char *fp, int count)
-{
-       struct gsm_mux *gsm = tty->disc_data;
-       const unsigned char *dp;
-       char *f;
-       int i;
-       char buf[64];
-       char flags;
-
-       if (debug & 4) {
-               printk("Inbytes %dd\n", count);
-               hex_packet(cp, count);
-       }
-
-       for (i = count, dp = cp, f = fp; i; i--, dp++) {
-               flags = *f++;
-               switch (flags) {
-               case TTY_NORMAL:
-                       gsm->receive(gsm, *dp);
-                       break;
-               case TTY_OVERRUN:
-               case TTY_BREAK:
-               case TTY_PARITY:
-               case TTY_FRAME:
-                       gsm->error(gsm, *dp, flags);
-                       break;
-               default:
-                       printk(KERN_ERR "%s: unknown flag %d\n",
-                              tty_name(tty, buf), flags);
-                       break;
-               }
-       }
-       /* FASYNC if needed ? */
-       /* If clogged call tty_throttle(tty); */
-}
-
-/**
- *     gsmld_chars_in_buffer   -       report available bytes
- *     @tty: tty device
- *
- *     Report the number of characters buffered to be delivered to user
- *     at this instant in time.
- *
- *     Locking: gsm lock
- */
-
-static ssize_t gsmld_chars_in_buffer(struct tty_struct *tty)
-{
-       return 0;
-}
-
-/**
- *     gsmld_flush_buffer      -       clean input queue
- *     @tty:   terminal device
- *
- *     Flush the input buffer. Called when the line discipline is
- *     being closed, when the tty layer wants the buffer flushed (eg
- *     at hangup).
- */
-
-static void gsmld_flush_buffer(struct tty_struct *tty)
-{
-}
-
-/**
- *     gsmld_close             -       close the ldisc for this tty
- *     @tty: device
- *
- *     Called from the terminal layer when this line discipline is
- *     being shut down, either because of a close or becsuse of a
- *     discipline change. The function will not be called while other
- *     ldisc methods are in progress.
- */
-
-static void gsmld_close(struct tty_struct *tty)
-{
-       struct gsm_mux *gsm = tty->disc_data;
-
-       gsmld_detach_gsm(tty, gsm);
-
-       gsmld_flush_buffer(tty);
-       /* Do other clean up here */
-       gsm_free_mux(gsm);
-}
-
-/**
- *     gsmld_open              -       open an ldisc
- *     @tty: terminal to open
- *
- *     Called when this line discipline is being attached to the
- *     terminal device. Can sleep. Called serialized so that no
- *     other events will occur in parallel. No further open will occur
- *     until a close.
- */
-
-static int gsmld_open(struct tty_struct *tty)
-{
-       struct gsm_mux *gsm;
-
-       if (tty->ops->write == NULL)
-               return -EINVAL;
-
-       /* Attach our ldisc data */
-       gsm = gsm_alloc_mux();
-       if (gsm == NULL)
-               return -ENOMEM;
-
-       tty->disc_data = gsm;
-       tty->receive_room = 65536;
-
-       /* Attach the initial passive connection */
-       gsm->encoding = 1;
-       return gsmld_attach_gsm(tty, gsm);
-}
-
-/**
- *     gsmld_write_wakeup      -       asynchronous I/O notifier
- *     @tty: tty device
- *
- *     Required for the ptys, serial driver etc. since processes
- *     that attach themselves to the master and rely on ASYNC
- *     IO must be woken up
- */
-
-static void gsmld_write_wakeup(struct tty_struct *tty)
-{
-       struct gsm_mux *gsm = tty->disc_data;
-       unsigned long flags;
-
-       /* Queue poll */
-       clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-       gsm_data_kick(gsm);
-       if (gsm->tx_bytes < TX_THRESH_LO) {
-               spin_lock_irqsave(&gsm->tx_lock, flags);
-               gsm_dlci_data_sweep(gsm);
-               spin_unlock_irqrestore(&gsm->tx_lock, flags);
-       }
-}
-
-/**
- *     gsmld_read              -       read function for tty
- *     @tty: tty device
- *     @file: file object
- *     @buf: userspace buffer pointer
- *     @nr: size of I/O
- *
- *     Perform reads for the line discipline. We are guaranteed that the
- *     line discipline will not be closed under us but we may get multiple
- *     parallel readers and must handle this ourselves. We may also get
- *     a hangup. Always called in user context, may sleep.
- *
- *     This code must be sure never to sleep through a hangup.
- */
-
-static ssize_t gsmld_read(struct tty_struct *tty, struct file *file,
-                        unsigned char __user *buf, size_t nr)
-{
-       return -EOPNOTSUPP;
-}
-
-/**
- *     gsmld_write             -       write function for tty
- *     @tty: tty device
- *     @file: file object
- *     @buf: userspace buffer pointer
- *     @nr: size of I/O
- *
- *     Called when the owner of the device wants to send a frame
- *     itself (or some other control data). The data is transferred
- *     as-is and must be properly framed and checksummed as appropriate
- *     by userspace. Frames are either sent whole or not at all as this
- *     avoids pain user side.
- */
-
-static ssize_t gsmld_write(struct tty_struct *tty, struct file *file,
-                          const unsigned char *buf, size_t nr)
-{
-       int space = tty_write_room(tty);
-       if (space >= nr)
-               return tty->ops->write(tty, buf, nr);
-       set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-       return -ENOBUFS;
-}
-
-/**
- *     gsmld_poll              -       poll method for N_GSM0710
- *     @tty: terminal device
- *     @file: file accessing it
- *     @wait: poll table
- *
- *     Called when the line discipline is asked to poll() for data or
- *     for special events. This code is not serialized with respect to
- *     other events save open/close.
- *
- *     This code must be sure never to sleep through a hangup.
- *     Called without the kernel lock held - fine
- */
-
-static unsigned int gsmld_poll(struct tty_struct *tty, struct file *file,
-                                                       poll_table *wait)
-{
-       unsigned int mask = 0;
-       struct gsm_mux *gsm = tty->disc_data;
-
-       poll_wait(file, &tty->read_wait, wait);
-       poll_wait(file, &tty->write_wait, wait);
-       if (tty_hung_up_p(file))
-               mask |= POLLHUP;
-       if (!tty_is_writelocked(tty) && tty_write_room(tty) > 0)
-               mask |= POLLOUT | POLLWRNORM;
-       if (gsm->dead)
-               mask |= POLLHUP;
-       return mask;
-}
-
-static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm,
-                                                       struct gsm_config *c)
-{
-       int need_close = 0;
-       int need_restart = 0;
-
-       /* Stuff we don't support yet - UI or I frame transport, windowing */
-       if ((c->adaption !=1 && c->adaption != 2) || c->k)
-               return -EOPNOTSUPP;
-       /* Check the MRU/MTU range looks sane */
-       if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8)
-               return -EINVAL;
-       if (c->n2 < 3)
-               return -EINVAL;
-       if (c->encapsulation > 1)       /* Basic, advanced, no I */
-               return -EINVAL;
-       if (c->initiator > 1)
-               return -EINVAL;
-       if (c->i == 0 || c->i > 2)      /* UIH and UI only */
-               return -EINVAL;
-       /*
-        *      See what is needed for reconfiguration
-        */
-
-       /* Timing fields */
-       if (c->t1 != 0 && c->t1 != gsm->t1)
-               need_restart = 1;
-       if (c->t2 != 0 && c->t2 != gsm->t2)
-               need_restart = 1;
-       if (c->encapsulation != gsm->encoding)
-               need_restart = 1;
-       if (c->adaption != gsm->adaption)
-               need_restart = 1;
-       /* Requires care */
-       if (c->initiator != gsm->initiator)
-               need_close = 1;
-       if (c->mru != gsm->mru)
-               need_restart = 1;
-       if (c->mtu != gsm->mtu)
-               need_restart = 1;
-
-       /*
-        *      Close down what is needed, restart and initiate the new
-        *      configuration
-        */
-
-       if (need_close || need_restart) {
-               gsm_dlci_begin_close(gsm->dlci[0]);
-               /* This will timeout if the link is down due to N2 expiring */
-               wait_event_interruptible(gsm->event,
-                               gsm->dlci[0]->state == DLCI_CLOSED);
-               if (signal_pending(current))
-                       return -EINTR;
-       }
-       if (need_restart)
-               gsm_cleanup_mux(gsm);
-
-       gsm->initiator = c->initiator;
-       gsm->mru = c->mru;
-       gsm->encoding = c->encapsulation;
-       gsm->adaption = c->adaption;
-
-       if (c->i == 1)
-               gsm->ftype = UIH;
-       else if (c->i == 2)
-               gsm->ftype = UI;
-
-       if (c->t1)
-               gsm->t1 = c->t1;
-       if (c->t2)
-               gsm->t2 = c->t2;
-
-       /* FIXME: We need to separate activation/deactivation from adding
-          and removing from the mux array */
-       if (need_restart)
-               gsm_activate_mux(gsm);
-       if (gsm->initiator && need_close)
-               gsm_dlci_begin_open(gsm->dlci[0]);
-       return 0;
-}
-
-static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       struct gsm_config c;
-       struct gsm_mux *gsm = tty->disc_data;
-
-       switch (cmd) {
-       case GSMIOC_GETCONF:
-               memset(&c, 0, sizeof(c));
-               c.adaption = gsm->adaption;
-               c.encapsulation = gsm->encoding;
-               c.initiator = gsm->initiator;
-               c.t1 = gsm->t1;
-               c.t2 = gsm->t2;
-               c.t3 = 0;       /* Not supported */
-               c.n2 = gsm->n2;
-               if (gsm->ftype == UIH)
-                       c.i = 1;
-               else
-                       c.i = 2;
-               printk("Ftype %d i %d\n", gsm->ftype, c.i);
-               c.mru = gsm->mru;
-               c.mtu = gsm->mtu;
-               c.k = 0;
-               if (copy_to_user((void *)arg, &c, sizeof(c)))
-                       return -EFAULT;
-               return 0;
-       case GSMIOC_SETCONF:
-               if (copy_from_user(&c, (void *)arg, sizeof(c)))
-                       return -EFAULT;
-               return gsmld_config(tty, gsm, &c);
-       default:
-               return n_tty_ioctl_helper(tty, file, cmd, arg);
-       }
-}
-
-
-/* Line discipline for real tty */
-struct tty_ldisc_ops tty_ldisc_packet = {
-       .owner           = THIS_MODULE,
-       .magic           = TTY_LDISC_MAGIC,
-       .name            = "n_gsm",
-       .open            = gsmld_open,
-       .close           = gsmld_close,
-       .flush_buffer    = gsmld_flush_buffer,
-       .chars_in_buffer = gsmld_chars_in_buffer,
-       .read            = gsmld_read,
-       .write           = gsmld_write,
-       .ioctl           = gsmld_ioctl,
-       .poll            = gsmld_poll,
-       .receive_buf     = gsmld_receive_buf,
-       .write_wakeup    = gsmld_write_wakeup
-};
-
-/*
- *     Virtual tty side
- */
-
-#define TX_SIZE                512
-
-static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk)
-{
-       u8 modembits[5];
-       struct gsm_control *ctrl;
-       int len = 2;
-
-       if (brk)
-               len++;
-
-       modembits[0] = len << 1 | EA;           /* Data bytes */
-       modembits[1] = dlci->addr << 2 | 3;     /* DLCI, EA, 1 */
-       modembits[2] = gsm_encode_modem(dlci) << 1 | EA;
-       if (brk)
-               modembits[3] = brk << 4 | 2 | EA;       /* Valid, EA */
-       ctrl = gsm_control_send(dlci->gsm, CMD_MSC, modembits, len + 1);
-       if (ctrl == NULL)
-               return -ENOMEM;
-       return gsm_control_wait(dlci->gsm, ctrl);
-}
-
-static int gsm_carrier_raised(struct tty_port *port)
-{
-       struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
-       /* Not yet open so no carrier info */
-       if (dlci->state != DLCI_OPEN)
-               return 0;
-       if (debug & 2)
-               return 1;
-       return dlci->modem_rx & TIOCM_CD;
-}
-
-static void gsm_dtr_rts(struct tty_port *port, int onoff)
-{
-       struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
-       unsigned int modem_tx = dlci->modem_tx;
-       if (onoff)
-               modem_tx |= TIOCM_DTR | TIOCM_RTS;
-       else
-               modem_tx &= ~(TIOCM_DTR | TIOCM_RTS);
-       if (modem_tx != dlci->modem_tx) {
-               dlci->modem_tx = modem_tx;
-               gsmtty_modem_update(dlci, 0);
-       }
-}
-
-static const struct tty_port_operations gsm_port_ops = {
-       .carrier_raised = gsm_carrier_raised,
-       .dtr_rts = gsm_dtr_rts,
-};
-
-
-static int gsmtty_open(struct tty_struct *tty, struct file *filp)
-{
-       struct gsm_mux *gsm;
-       struct gsm_dlci *dlci;
-       struct tty_port *port;
-       unsigned int line = tty->index;
-       unsigned int mux = line >> 6;
-
-       line = line & 0x3F;
-
-       if (mux >= MAX_MUX)
-               return -ENXIO;
-       /* FIXME: we need to lock gsm_mux for lifetimes of ttys eventually */
-       if (gsm_mux[mux] == NULL)
-               return -EUNATCH;
-       if (line == 0 || line > 61)     /* 62/63 reserved */
-               return -ECHRNG;
-       gsm = gsm_mux[mux];
-       if (gsm->dead)
-               return -EL2HLT;
-       dlci = gsm->dlci[line];
-       if (dlci == NULL)
-               dlci = gsm_dlci_alloc(gsm, line);
-       if (dlci == NULL)
-               return -ENOMEM;
-       port = &dlci->port;
-       port->count++;
-       tty->driver_data = dlci;
-       tty_port_tty_set(port, tty);
-
-       dlci->modem_rx = 0;
-       /* We could in theory open and close before we wait - eg if we get
-          a DM straight back. This is ok as that will have caused a hangup */
-       set_bit(ASYNCB_INITIALIZED, &port->flags);
-       /* Start sending off SABM messages */
-       gsm_dlci_begin_open(dlci);
-       /* And wait for virtual carrier */
-       return tty_port_block_til_ready(port, tty, filp);
-}
-
-static void gsmtty_close(struct tty_struct *tty, struct file *filp)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       if (dlci == NULL)
-               return;
-       if (tty_port_close_start(&dlci->port, tty, filp) == 0)
-               return;
-       gsm_dlci_begin_close(dlci);
-       tty_port_close_end(&dlci->port, tty);
-       tty_port_tty_set(&dlci->port, NULL);
-}
-
-static void gsmtty_hangup(struct tty_struct *tty)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       tty_port_hangup(&dlci->port);
-       gsm_dlci_begin_close(dlci);
-}
-
-static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf,
-                                                                   int len)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       /* Stuff the bytes into the fifo queue */
-       int sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock);
-       /* Need to kick the channel */
-       gsm_dlci_data_kick(dlci);
-       return sent;
-}
-
-static int gsmtty_write_room(struct tty_struct *tty)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       return TX_SIZE - kfifo_len(dlci->fifo);
-}
-
-static int gsmtty_chars_in_buffer(struct tty_struct *tty)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       return kfifo_len(dlci->fifo);
-}
-
-static void gsmtty_flush_buffer(struct tty_struct *tty)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       /* Caution needed: If we implement reliable transport classes
-          then the data being transmitted can't simply be junked once
-          it has first hit the stack. Until then we can just blow it
-          away */
-       kfifo_reset(dlci->fifo);
-       /* Need to unhook this DLCI from the transmit queue logic */
-}
-
-static void gsmtty_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-       /* The FIFO handles the queue so the kernel will do the right
-          thing waiting on chars_in_buffer before calling us. No work
-          to do here */
-}
-
-static int gsmtty_tiocmget(struct tty_struct *tty, struct file *filp)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       return dlci->modem_rx;
-}
-
-static int gsmtty_tiocmset(struct tty_struct *tty, struct file *filp,
-       unsigned int set, unsigned int clear)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       unsigned int modem_tx = dlci->modem_tx;
-
-       modem_tx &= clear;
-       modem_tx |= set;
-
-       if (modem_tx != dlci->modem_tx) {
-               dlci->modem_tx = modem_tx;
-               return gsmtty_modem_update(dlci, 0);
-       }
-       return 0;
-}
-
-
-static int gsmtty_ioctl(struct tty_struct *tty, struct file *filp,
-                       unsigned int cmd, unsigned long arg)
-{
-       return -ENOIOCTLCMD;
-}
-
-static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
-{
-       /* For the moment its fixed. In actual fact the speed information
-          for the virtual channel can be propogated in both directions by
-          the RPN control message. This however rapidly gets nasty as we
-          then have to remap modem signals each way according to whether
-          our virtual cable is null modem etc .. */
-       tty_termios_copy_hw(tty->termios, old);
-}
-
-static void gsmtty_throttle(struct tty_struct *tty)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       if (tty->termios->c_cflag & CRTSCTS)
-               dlci->modem_tx &= ~TIOCM_DTR;
-       dlci->throttled = 1;
-       /* Send an MSC with DTR cleared */
-       gsmtty_modem_update(dlci, 0);
-}
-
-static void gsmtty_unthrottle(struct tty_struct *tty)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       if (tty->termios->c_cflag & CRTSCTS)
-               dlci->modem_tx |= TIOCM_DTR;
-       dlci->throttled = 0;
-       /* Send an MSC with DTR set */
-       gsmtty_modem_update(dlci, 0);
-}
-
-static int gsmtty_break_ctl(struct tty_struct *tty, int state)
-{
-       struct gsm_dlci *dlci = tty->driver_data;
-       int encode = 0; /* Off */
-
-       if (state == -1)        /* "On indefinitely" - we can't encode this
-                                   properly */
-               encode = 0x0F;
-       else if (state > 0) {
-               encode = state / 200;   /* mS to encoding */
-               if (encode > 0x0F)
-                       encode = 0x0F;  /* Best effort */
-       }
-       return gsmtty_modem_update(dlci, encode);
-}
-
-static struct tty_driver *gsm_tty_driver;
-
-/* Virtual ttys for the demux */
-static const struct tty_operations gsmtty_ops = {
-       .open                   = gsmtty_open,
-       .close                  = gsmtty_close,
-       .write                  = gsmtty_write,
-       .write_room             = gsmtty_write_room,
-       .chars_in_buffer        = gsmtty_chars_in_buffer,
-       .flush_buffer           = gsmtty_flush_buffer,
-       .ioctl                  = gsmtty_ioctl,
-       .throttle               = gsmtty_throttle,
-       .unthrottle             = gsmtty_unthrottle,
-       .set_termios            = gsmtty_set_termios,
-       .hangup                 = gsmtty_hangup,
-       .wait_until_sent        = gsmtty_wait_until_sent,
-       .tiocmget               = gsmtty_tiocmget,
-       .tiocmset               = gsmtty_tiocmset,
-       .break_ctl              = gsmtty_break_ctl,
-};
-
-
-
-static int __init gsm_init(void)
-{
-       /* Fill in our line protocol discipline, and register it */
-       int status = tty_register_ldisc(N_GSM0710, &tty_ldisc_packet);
-       if (status != 0) {
-               printk(KERN_ERR "n_gsm: can't register line discipline (err = %d)\n", status);
-               return status;
-       }
-
-       gsm_tty_driver = alloc_tty_driver(256);
-       if (!gsm_tty_driver) {
-               tty_unregister_ldisc(N_GSM0710);
-               printk(KERN_ERR "gsm_init: tty allocation failed.\n");
-               return -EINVAL;
-       }
-       gsm_tty_driver->owner   = THIS_MODULE;
-       gsm_tty_driver->driver_name     = "gsmtty";
-       gsm_tty_driver->name            = "gsmtty";
-       gsm_tty_driver->major           = 0;    /* Dynamic */
-       gsm_tty_driver->minor_start     = 0;
-       gsm_tty_driver->type            = TTY_DRIVER_TYPE_SERIAL;
-       gsm_tty_driver->subtype = SERIAL_TYPE_NORMAL;
-       gsm_tty_driver->flags   = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV
-                                                       | TTY_DRIVER_HARDWARE_BREAK;
-       gsm_tty_driver->init_termios    = tty_std_termios;
-       /* Fixme */
-       gsm_tty_driver->init_termios.c_lflag &= ~ECHO;
-       tty_set_operations(gsm_tty_driver, &gsmtty_ops);
-
-       spin_lock_init(&gsm_mux_lock);
-
-       if (tty_register_driver(gsm_tty_driver)) {
-               put_tty_driver(gsm_tty_driver);
-               tty_unregister_ldisc(N_GSM0710);
-               printk(KERN_ERR "gsm_init: tty registration failed.\n");
-               return -EBUSY;
-       }
-       printk(KERN_INFO "gsm_init: loaded as %d,%d.\n", gsm_tty_driver->major, gsm_tty_driver->minor_start);
-       return 0;
-}
-
-static void __exit gsm_exit(void)
-{
-       int status = tty_unregister_ldisc(N_GSM0710);
-       if (status != 0)
-               printk(KERN_ERR "n_gsm: can't unregister line discipline (err = %d)\n", status);
-       tty_unregister_driver(gsm_tty_driver);
-       put_tty_driver(gsm_tty_driver);
-       printk(KERN_INFO "gsm_init: unloaded.\n");
-}
-
-module_init(gsm_init);
-module_exit(gsm_exit);
-
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_LDISC(N_GSM0710);
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
deleted file mode 100644 (file)
index 47d3228..0000000
+++ /dev/null
@@ -1,1007 +0,0 @@
-/* generic HDLC line discipline for Linux
- *
- * Written by Paul Fulghum paulkf@microgate.com
- * for Microgate Corporation
- *
- * Microgate and SyncLink are registered trademarks of Microgate Corporation
- *
- * Adapted from ppp.c, written by Michael Callahan <callahan@maths.ox.ac.uk>,
- *     Al Longyear <longyear@netcom.com>,
- *     Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
- *
- * Original release 01/11/99
- *
- * This code is released under the GNU General Public License (GPL)
- *
- * This module implements the tty line discipline N_HDLC for use with
- * tty device drivers that support bit-synchronous HDLC communications.
- *
- * All HDLC data is frame oriented which means:
- *
- * 1. tty write calls represent one complete transmit frame of data
- *    The device driver should accept the complete frame or none of 
- *    the frame (busy) in the write method. Each write call should have
- *    a byte count in the range of 2-65535 bytes (2 is min HDLC frame
- *    with 1 addr byte and 1 ctrl byte). The max byte count of 65535
- *    should include any crc bytes required. For example, when using
- *    CCITT CRC32, 4 crc bytes are required, so the maximum size frame
- *    the application may transmit is limited to 65531 bytes. For CCITT
- *    CRC16, the maximum application frame size would be 65533.
- *
- *
- * 2. receive callbacks from the device driver represents
- *    one received frame. The device driver should bypass
- *    the tty flip buffer and call the line discipline receive
- *    callback directly to avoid fragmenting or concatenating
- *    multiple frames into a single receive callback.
- *
- *    The HDLC line discipline queues the receive frames in separate
- *    buffers so complete receive frames can be returned by the
- *    tty read calls.
- *
- * 3. tty read calls returns an entire frame of data or nothing.
- *    
- * 4. all send and receive data is considered raw. No processing
- *    or translation is performed by the line discipline, regardless
- *    of the tty flags
- *
- * 5. When line discipline is queried for the amount of receive
- *    data available (FIOC), 0 is returned if no data available,
- *    otherwise the count of the next available frame is returned.
- *    (instead of the sum of all received frame counts).
- *
- * These conventions allow the standard tty programming interface
- * to be used for synchronous HDLC applications when used with
- * this line discipline (or another line discipline that is frame
- * oriented such as N_PPP).
- *
- * The SyncLink driver (synclink.c) implements both asynchronous
- * (using standard line discipline N_TTY) and synchronous HDLC
- * (using N_HDLC) communications, with the latter using the above
- * conventions.
- *
- * This implementation is very basic and does not maintain
- * any statistics. The main point is to enforce the raw data
- * and frame orientation of HDLC communications.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define HDLC_MAGIC 0x239e
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-
-#undef VERSION
-#define VERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
-
-#include <linux/poll.h>
-#include <linux/in.h>
-#include <linux/ioctl.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/smp_lock.h>
-#include <linux/string.h>      /* used in new tty drivers */
-#include <linux/signal.h>      /* used in new tty drivers */
-#include <linux/if.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
-#include <asm/termios.h>
-#include <asm/uaccess.h>
-
-/*
- * Buffers for individual HDLC frames
- */
-#define MAX_HDLC_FRAME_SIZE 65535 
-#define DEFAULT_RX_BUF_COUNT 10
-#define MAX_RX_BUF_COUNT 60
-#define DEFAULT_TX_BUF_COUNT 3
-
-struct n_hdlc_buf {
-       struct n_hdlc_buf *link;
-       int               count;
-       char              buf[1];
-};
-
-#define        N_HDLC_BUF_SIZE (sizeof(struct n_hdlc_buf) + maxframe)
-
-struct n_hdlc_buf_list {
-       struct n_hdlc_buf *head;
-       struct n_hdlc_buf *tail;
-       int               count;
-       spinlock_t        spinlock;
-};
-
-/**
- * struct n_hdlc - per device instance data structure
- * @magic - magic value for structure
- * @flags - miscellaneous control flags
- * @tty - ptr to TTY structure
- * @backup_tty - TTY to use if tty gets closed
- * @tbusy - reentrancy flag for tx wakeup code
- * @woke_up - FIXME: describe this field
- * @tbuf - currently transmitting tx buffer
- * @tx_buf_list - list of pending transmit frame buffers
- * @rx_buf_list - list of received frame buffers
- * @tx_free_buf_list - list unused transmit frame buffers
- * @rx_free_buf_list - list unused received frame buffers
- */
-struct n_hdlc {
-       int                     magic;
-       __u32                   flags;
-       struct tty_struct       *tty;
-       struct tty_struct       *backup_tty;
-       int                     tbusy;
-       int                     woke_up;
-       struct n_hdlc_buf       *tbuf;
-       struct n_hdlc_buf_list  tx_buf_list;
-       struct n_hdlc_buf_list  rx_buf_list;
-       struct n_hdlc_buf_list  tx_free_buf_list;
-       struct n_hdlc_buf_list  rx_free_buf_list;
-};
-
-/*
- * HDLC buffer list manipulation functions
- */
-static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list);
-static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
-                          struct n_hdlc_buf *buf);
-static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
-
-/* Local functions */
-
-static struct n_hdlc *n_hdlc_alloc (void);
-
-/* debug level can be set by insmod for debugging purposes */
-#define DEBUG_LEVEL_INFO       1
-static int debuglevel;
-
-/* max frame size for memory allocations */
-static int maxframe = 4096;
-
-/* TTY callbacks */
-
-static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
-                          __u8 __user *buf, size_t nr);
-static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
-                           const unsigned char *buf, size_t nr);
-static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
-                           unsigned int cmd, unsigned long arg);
-static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
-                                   poll_table *wait);
-static int n_hdlc_tty_open(struct tty_struct *tty);
-static void n_hdlc_tty_close(struct tty_struct *tty);
-static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp,
-                              char *fp, int count);
-static void n_hdlc_tty_wakeup(struct tty_struct *tty);
-
-#define bset(p,b)      ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
-
-#define tty2n_hdlc(tty)        ((struct n_hdlc *) ((tty)->disc_data))
-#define n_hdlc2tty(n_hdlc)     ((n_hdlc)->tty)
-
-static void flush_rx_queue(struct tty_struct *tty)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
-       struct n_hdlc_buf *buf;
-
-       while ((buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list)))
-               n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, buf);
-}
-
-static void flush_tx_queue(struct tty_struct *tty)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
-       struct n_hdlc_buf *buf;
-       unsigned long flags;
-
-       while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list)))
-               n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf);
-       spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
-       if (n_hdlc->tbuf) {
-               n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, n_hdlc->tbuf);
-               n_hdlc->tbuf = NULL;
-       }
-       spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
-}
-
-static struct tty_ldisc_ops n_hdlc_ldisc = {
-       .owner          = THIS_MODULE,
-       .magic          = TTY_LDISC_MAGIC,
-       .name           = "hdlc",
-       .open           = n_hdlc_tty_open,
-       .close          = n_hdlc_tty_close,
-       .read           = n_hdlc_tty_read,
-       .write          = n_hdlc_tty_write,
-       .ioctl          = n_hdlc_tty_ioctl,
-       .poll           = n_hdlc_tty_poll,
-       .receive_buf    = n_hdlc_tty_receive,
-       .write_wakeup   = n_hdlc_tty_wakeup,
-       .flush_buffer   = flush_rx_queue,
-};
-
-/**
- * n_hdlc_release - release an n_hdlc per device line discipline info structure
- * @n_hdlc - per device line discipline info structure
- */
-static void n_hdlc_release(struct n_hdlc *n_hdlc)
-{
-       struct tty_struct *tty = n_hdlc2tty (n_hdlc);
-       struct n_hdlc_buf *buf;
-       
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_release() called\n",__FILE__,__LINE__);
-               
-       /* Ensure that the n_hdlcd process is not hanging on select()/poll() */
-       wake_up_interruptible (&tty->read_wait);
-       wake_up_interruptible (&tty->write_wait);
-
-       if (tty->disc_data == n_hdlc)
-               tty->disc_data = NULL;  /* Break the tty->n_hdlc link */
-
-       /* Release transmit and receive buffers */
-       for(;;) {
-               buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
-               if (buf) {
-                       kfree(buf);
-               } else
-                       break;
-       }
-       for(;;) {
-               buf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);
-               if (buf) {
-                       kfree(buf);
-               } else
-                       break;
-       }
-       for(;;) {
-               buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
-               if (buf) {
-                       kfree(buf);
-               } else
-                       break;
-       }
-       for(;;) {
-               buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
-               if (buf) {
-                       kfree(buf);
-               } else
-                       break;
-       }
-       kfree(n_hdlc->tbuf);
-       kfree(n_hdlc);
-       
-}      /* end of n_hdlc_release() */
-
-/**
- * n_hdlc_tty_close - line discipline close
- * @tty - pointer to tty info structure
- *
- * Called when the line discipline is changed to something
- * else, the tty is closed, or the tty detects a hangup.
- */
-static void n_hdlc_tty_close(struct tty_struct *tty)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_close() called\n",__FILE__,__LINE__);
-               
-       if (n_hdlc != NULL) {
-               if (n_hdlc->magic != HDLC_MAGIC) {
-                       printk (KERN_WARNING"n_hdlc: trying to close unopened tty!\n");
-                       return;
-               }
-#if defined(TTY_NO_WRITE_SPLIT)
-               clear_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
-#endif
-               tty->disc_data = NULL;
-               if (tty == n_hdlc->backup_tty)
-                       n_hdlc->backup_tty = NULL;
-               if (tty != n_hdlc->tty)
-                       return;
-               if (n_hdlc->backup_tty) {
-                       n_hdlc->tty = n_hdlc->backup_tty;
-               } else {
-                       n_hdlc_release (n_hdlc);
-               }
-       }
-       
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_close() success\n",__FILE__,__LINE__);
-               
-}      /* end of n_hdlc_tty_close() */
-
-/**
- * n_hdlc_tty_open - called when line discipline changed to n_hdlc
- * @tty - pointer to tty info structure
- *
- * Returns 0 if success, otherwise error code
- */
-static int n_hdlc_tty_open (struct tty_struct *tty)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_open() called (device=%s)\n",
-               __FILE__,__LINE__,
-               tty->name);
-               
-       /* There should not be an existing table for this slot. */
-       if (n_hdlc) {
-               printk (KERN_ERR"n_hdlc_tty_open:tty already associated!\n" );
-               return -EEXIST;
-       }
-       
-       n_hdlc = n_hdlc_alloc();
-       if (!n_hdlc) {
-               printk (KERN_ERR "n_hdlc_alloc failed\n");
-               return -ENFILE;
-       }
-               
-       tty->disc_data = n_hdlc;
-       n_hdlc->tty    = tty;
-       tty->receive_room = 65536;
-       
-#if defined(TTY_NO_WRITE_SPLIT)
-       /* change tty_io write() to not split large writes into 8K chunks */
-       set_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
-#endif
-       
-       /* flush receive data from driver */
-       tty_driver_flush_buffer(tty);
-               
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_open() success\n",__FILE__,__LINE__);
-               
-       return 0;
-       
-}      /* end of n_tty_hdlc_open() */
-
-/**
- * n_hdlc_send_frames - send frames on pending send buffer list
- * @n_hdlc - pointer to ldisc instance data
- * @tty - pointer to tty instance data
- *
- * Send frames on pending send buffer list until the driver does not accept a
- * frame (busy) this function is called after adding a frame to the send buffer
- * list and by the tty wakeup callback.
- */
-static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
-{
-       register int actual;
-       unsigned long flags;
-       struct n_hdlc_buf *tbuf;
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__);
- check_again:
-               
-       spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
-       if (n_hdlc->tbusy) {
-               n_hdlc->woke_up = 1;
-               spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
-               return;
-       }
-       n_hdlc->tbusy = 1;
-       n_hdlc->woke_up = 0;
-       spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
-
-       /* get current transmit buffer or get new transmit */
-       /* buffer from list of pending transmit buffers */
-               
-       tbuf = n_hdlc->tbuf;
-       if (!tbuf)
-               tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
-               
-       while (tbuf) {
-               if (debuglevel >= DEBUG_LEVEL_INFO)     
-                       printk("%s(%d)sending frame %p, count=%d\n",
-                               __FILE__,__LINE__,tbuf,tbuf->count);
-                       
-               /* Send the next block of data to device */
-               tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
-               actual = tty->ops->write(tty, tbuf->buf, tbuf->count);
-
-               /* rollback was possible and has been done */
-               if (actual == -ERESTARTSYS) {
-                       n_hdlc->tbuf = tbuf;
-                       break;
-               }
-               /* if transmit error, throw frame away by */
-               /* pretending it was accepted by driver */
-               if (actual < 0)
-                       actual = tbuf->count;
-               
-               if (actual == tbuf->count) {
-                       if (debuglevel >= DEBUG_LEVEL_INFO)     
-                               printk("%s(%d)frame %p completed\n",
-                                       __FILE__,__LINE__,tbuf);
-                                       
-                       /* free current transmit buffer */
-                       n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf);
-                       
-                       /* this tx buffer is done */
-                       n_hdlc->tbuf = NULL;
-                       
-                       /* wait up sleeping writers */
-                       wake_up_interruptible(&tty->write_wait);
-       
-                       /* get next pending transmit buffer */
-                       tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
-               } else {
-                       if (debuglevel >= DEBUG_LEVEL_INFO)     
-                               printk("%s(%d)frame %p pending\n",
-                                       __FILE__,__LINE__,tbuf);
-                                       
-                       /* buffer not accepted by driver */
-                       /* set this buffer as pending buffer */
-                       n_hdlc->tbuf = tbuf;
-                       break;
-               }
-       }
-       
-       if (!tbuf)
-               tty->flags  &= ~(1 << TTY_DO_WRITE_WAKEUP);
-       
-       /* Clear the re-entry flag */
-       spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
-       n_hdlc->tbusy = 0;
-       spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); 
-       
-        if (n_hdlc->woke_up)
-         goto check_again;
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_send_frames() exit\n",__FILE__,__LINE__);
-               
-}      /* end of n_hdlc_send_frames() */
-
-/**
- * n_hdlc_tty_wakeup - Callback for transmit wakeup
- * @tty        - pointer to associated tty instance data
- *
- * Called when low level device driver can accept more send data.
- */
-static void n_hdlc_tty_wakeup(struct tty_struct *tty)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_wakeup() called\n",__FILE__,__LINE__);
-               
-       if (!n_hdlc)
-               return;
-
-       if (tty != n_hdlc->tty) {
-               tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
-               return;
-       }
-
-       n_hdlc_send_frames (n_hdlc, tty);
-               
-}      /* end of n_hdlc_tty_wakeup() */
-
-/**
- * n_hdlc_tty_receive - Called by tty driver when receive data is available
- * @tty        - pointer to tty instance data
- * @data - pointer to received data
- * @flags - pointer to flags for data
- * @count - count of received data in bytes
- *
- * Called by tty low level driver when receive data is available. Data is
- * interpreted as one HDLC frame.
- */
-static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
-                              char *flags, int count)
-{
-       register struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-       register struct n_hdlc_buf *buf;
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_receive() called count=%d\n",
-                       __FILE__,__LINE__, count);
-               
-       /* This can happen if stuff comes in on the backup tty */
-       if (!n_hdlc || tty != n_hdlc->tty)
-               return;
-               
-       /* verify line is using HDLC discipline */
-       if (n_hdlc->magic != HDLC_MAGIC) {
-               printk("%s(%d) line not using HDLC discipline\n",
-                       __FILE__,__LINE__);
-               return;
-       }
-       
-       if ( count>maxframe ) {
-               if (debuglevel >= DEBUG_LEVEL_INFO)     
-                       printk("%s(%d) rx count>maxframesize, data discarded\n",
-                              __FILE__,__LINE__);
-               return;
-       }
-
-       /* get a free HDLC buffer */    
-       buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
-       if (!buf) {
-               /* no buffers in free list, attempt to allocate another rx buffer */
-               /* unless the maximum count has been reached */
-               if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT)
-                       buf = kmalloc(N_HDLC_BUF_SIZE, GFP_ATOMIC);
-       }
-       
-       if (!buf) {
-               if (debuglevel >= DEBUG_LEVEL_INFO)     
-                       printk("%s(%d) no more rx buffers, data discarded\n",
-                              __FILE__,__LINE__);
-               return;
-       }
-               
-       /* copy received data to HDLC buffer */
-       memcpy(buf->buf,data,count);
-       buf->count=count;
-
-       /* add HDLC buffer to list of received frames */
-       n_hdlc_buf_put(&n_hdlc->rx_buf_list, buf);
-       
-       /* wake up any blocked reads and perform async signalling */
-       wake_up_interruptible (&tty->read_wait);
-       if (n_hdlc->tty->fasync != NULL)
-               kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN);
-
-}      /* end of n_hdlc_tty_receive() */
-
-/**
- * n_hdlc_tty_read - Called to retrieve one frame of data (if available)
- * @tty - pointer to tty instance data
- * @file - pointer to open file object
- * @buf - pointer to returned data buffer
- * @nr - size of returned data buffer
- *     
- * Returns the number of bytes returned or error code.
- */
-static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
-                          __u8 __user *buf, size_t nr)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
-       int ret;
-       struct n_hdlc_buf *rbuf;
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__);
-               
-       /* Validate the pointers */
-       if (!n_hdlc)
-               return -EIO;
-
-       /* verify user access to buffer */
-       if (!access_ok(VERIFY_WRITE, buf, nr)) {
-               printk(KERN_WARNING "%s(%d) n_hdlc_tty_read() can't verify user "
-               "buffer\n", __FILE__, __LINE__);
-               return -EFAULT;
-       }
-
-       tty_lock();
-
-       for (;;) {
-               if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
-                       tty_unlock();
-                       return -EIO;
-               }
-
-               n_hdlc = tty2n_hdlc (tty);
-               if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC ||
-                        tty != n_hdlc->tty) {
-                       tty_unlock();
-                       return 0;
-               }
-
-               rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
-               if (rbuf)
-                       break;
-                       
-               /* no data */
-               if (file->f_flags & O_NONBLOCK) {
-                       tty_unlock();
-                       return -EAGAIN;
-               }
-                       
-               interruptible_sleep_on (&tty->read_wait);
-               if (signal_pending(current)) {
-                       tty_unlock();
-                       return -EINTR;
-               }
-       }
-               
-       if (rbuf->count > nr)
-               /* frame too large for caller's buffer (discard frame) */
-               ret = -EOVERFLOW;
-       else {
-               /* Copy the data to the caller's buffer */
-               if (copy_to_user(buf, rbuf->buf, rbuf->count))
-                       ret = -EFAULT;
-               else
-                       ret = rbuf->count;
-       }
-       
-       /* return HDLC buffer to free list unless the free list */
-       /* count has exceeded the default value, in which case the */
-       /* buffer is freed back to the OS to conserve memory */
-       if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT)
-               kfree(rbuf);
-       else    
-               n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf);
-       tty_unlock();
-       return ret;
-       
-}      /* end of n_hdlc_tty_read() */
-
-/**
- * n_hdlc_tty_write - write a single frame of data to device
- * @tty        - pointer to associated tty device instance data
- * @file - pointer to file object data
- * @data - pointer to transmit data (one frame)
- * @count - size of transmit frame in bytes
- *             
- * Returns the number of bytes written (or error code).
- */
-static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
-                           const unsigned char *data, size_t count)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-       int error = 0;
-       DECLARE_WAITQUEUE(wait, current);
-       struct n_hdlc_buf *tbuf;
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_write() called count=%Zd\n",
-                       __FILE__,__LINE__,count);
-               
-       /* Verify pointers */
-       if (!n_hdlc)
-               return -EIO;
-
-       if (n_hdlc->magic != HDLC_MAGIC)
-               return -EIO;
-
-       /* verify frame size */
-       if (count > maxframe ) {
-               if (debuglevel & DEBUG_LEVEL_INFO)
-                       printk (KERN_WARNING
-                               "n_hdlc_tty_write: truncating user packet "
-                               "from %lu to %d\n", (unsigned long) count,
-                               maxframe );
-               count = maxframe;
-       }
-       
-       tty_lock();
-
-       add_wait_queue(&tty->write_wait, &wait);
-       set_current_state(TASK_INTERRUPTIBLE);
-       
-       /* Allocate transmit buffer */
-       /* sleep until transmit buffer available */             
-       while (!(tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list))) {
-               if (file->f_flags & O_NONBLOCK) {
-                       error = -EAGAIN;
-                       break;
-               }
-               schedule();
-                       
-               n_hdlc = tty2n_hdlc (tty);
-               if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || 
-                   tty != n_hdlc->tty) {
-                       printk("n_hdlc_tty_write: %p invalid after wait!\n", n_hdlc);
-                       error = -EIO;
-                       break;
-               }
-                       
-               if (signal_pending(current)) {
-                       error = -EINTR;
-                       break;
-               }
-       }
-
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&tty->write_wait, &wait);
-
-       if (!error) {           
-               /* Retrieve the user's buffer */
-               memcpy(tbuf->buf, data, count);
-
-               /* Send the data */
-               tbuf->count = error = count;
-               n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf);
-               n_hdlc_send_frames(n_hdlc,tty);
-       }
-       tty_unlock();
-       return error;
-       
-}      /* end of n_hdlc_tty_write() */
-
-/**
- * n_hdlc_tty_ioctl - process IOCTL system call for the tty device.
- * @tty - pointer to tty instance data
- * @file - pointer to open file object for device
- * @cmd - IOCTL command code
- * @arg - argument for IOCTL call (cmd dependent)
- *
- * Returns command dependent result.
- */
-static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
-                           unsigned int cmd, unsigned long arg)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-       int error = 0;
-       int count;
-       unsigned long flags;
-       
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_ioctl() called %d\n",
-                       __FILE__,__LINE__,cmd);
-               
-       /* Verify the status of the device */
-       if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC)
-               return -EBADF;
-
-       switch (cmd) {
-       case FIONREAD:
-               /* report count of read data available */
-               /* in next available frame (if any) */
-               spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
-               if (n_hdlc->rx_buf_list.head)
-                       count = n_hdlc->rx_buf_list.head->count;
-               else
-                       count = 0;
-               spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
-               error = put_user(count, (int __user *)arg);
-               break;
-
-       case TIOCOUTQ:
-               /* get the pending tx byte count in the driver */
-               count = tty_chars_in_buffer(tty);
-               /* add size of next output frame in queue */
-               spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
-               if (n_hdlc->tx_buf_list.head)
-                       count += n_hdlc->tx_buf_list.head->count;
-               spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags);
-               error = put_user(count, (int __user *)arg);
-               break;
-
-       case TCFLSH:
-               switch (arg) {
-               case TCIOFLUSH:
-               case TCOFLUSH:
-                       flush_tx_queue(tty);
-               }
-               /* fall through to default */
-
-       default:
-               error = n_tty_ioctl_helper(tty, file, cmd, arg);
-               break;
-       }
-       return error;
-       
-}      /* end of n_hdlc_tty_ioctl() */
-
-/**
- * n_hdlc_tty_poll - TTY callback for poll system call
- * @tty - pointer to tty instance data
- * @filp - pointer to open file object for device
- * @poll_table - wait queue for operations
- * 
- * Determine which operations (read/write) will not block and return info
- * to caller.
- * Returns a bit mask containing info on which ops will not block.
- */
-static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
-                                   poll_table *wait)
-{
-       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
-       unsigned int mask = 0;
-
-       if (debuglevel >= DEBUG_LEVEL_INFO)     
-               printk("%s(%d)n_hdlc_tty_poll() called\n",__FILE__,__LINE__);
-               
-       if (n_hdlc && n_hdlc->magic == HDLC_MAGIC && tty == n_hdlc->tty) {
-               /* queue current process into any wait queue that */
-               /* may awaken in the future (read and write) */
-
-               poll_wait(filp, &tty->read_wait, wait);
-               poll_wait(filp, &tty->write_wait, wait);
-
-               /* set bits for operations that won't block */
-               if (n_hdlc->rx_buf_list.head)
-                       mask |= POLLIN | POLLRDNORM;    /* readable */
-               if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
-                       mask |= POLLHUP;
-               if (tty_hung_up_p(filp))
-                       mask |= POLLHUP;
-               if (!tty_is_writelocked(tty) &&
-                               n_hdlc->tx_free_buf_list.head)
-                       mask |= POLLOUT | POLLWRNORM;   /* writable */
-       }
-       return mask;
-}      /* end of n_hdlc_tty_poll() */
-
-/**
- * n_hdlc_alloc - allocate an n_hdlc instance data structure
- *
- * Returns a pointer to newly created structure if success, otherwise %NULL
- */
-static struct n_hdlc *n_hdlc_alloc(void)
-{
-       struct n_hdlc_buf *buf;
-       int i;
-       struct n_hdlc *n_hdlc = kmalloc(sizeof(*n_hdlc), GFP_KERNEL);
-
-       if (!n_hdlc)
-               return NULL;
-
-       memset(n_hdlc, 0, sizeof(*n_hdlc));
-
-       n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list);
-       n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list);
-       n_hdlc_buf_list_init(&n_hdlc->rx_buf_list);
-       n_hdlc_buf_list_init(&n_hdlc->tx_buf_list);
-       
-       /* allocate free rx buffer list */
-       for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
-               buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL);
-               if (buf)
-                       n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,buf);
-               else if (debuglevel >= DEBUG_LEVEL_INFO)        
-                       printk("%s(%d)n_hdlc_alloc(), kalloc() failed for rx buffer %d\n",__FILE__,__LINE__, i);
-       }
-       
-       /* allocate free tx buffer list */
-       for(i=0;i<DEFAULT_TX_BUF_COUNT;i++) {
-               buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL);
-               if (buf)
-                       n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,buf);
-               else if (debuglevel >= DEBUG_LEVEL_INFO)        
-                       printk("%s(%d)n_hdlc_alloc(), kalloc() failed for tx buffer %d\n",__FILE__,__LINE__, i);
-       }
-       
-       /* Initialize the control block */
-       n_hdlc->magic  = HDLC_MAGIC;
-       n_hdlc->flags  = 0;
-       
-       return n_hdlc;
-       
-}      /* end of n_hdlc_alloc() */
-
-/**
- * n_hdlc_buf_list_init - initialize specified HDLC buffer list
- * @list - pointer to buffer list
- */
-static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list)
-{
-       memset(list, 0, sizeof(*list));
-       spin_lock_init(&list->spinlock);
-}      /* end of n_hdlc_buf_list_init() */
-
-/**
- * n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
- * @list - pointer to buffer list
- * @buf        - pointer to buffer
- */
-static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
-                          struct n_hdlc_buf *buf)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&list->spinlock,flags);
-       
-       buf->link=NULL;
-       if (list->tail)
-               list->tail->link = buf;
-       else
-               list->head = buf;
-       list->tail = buf;
-       (list->count)++;
-       
-       spin_unlock_irqrestore(&list->spinlock,flags);
-       
-}      /* end of n_hdlc_buf_put() */
-
-/**
- * n_hdlc_buf_get - remove and return an HDLC buffer from list
- * @list - pointer to HDLC buffer list
- * 
- * Remove and return an HDLC buffer from the head of the specified HDLC buffer
- * list.
- * Returns a pointer to HDLC buffer if available, otherwise %NULL.
- */
-static struct n_hdlc_buf* n_hdlc_buf_get(struct n_hdlc_buf_list *list)
-{
-       unsigned long flags;
-       struct n_hdlc_buf *buf;
-       spin_lock_irqsave(&list->spinlock,flags);
-       
-       buf = list->head;
-       if (buf) {
-               list->head = buf->link;
-               (list->count)--;
-       }
-       if (!list->head)
-               list->tail = NULL;
-       
-       spin_unlock_irqrestore(&list->spinlock,flags);
-       return buf;
-       
-}      /* end of n_hdlc_buf_get() */
-
-static char hdlc_banner[] __initdata =
-       KERN_INFO "HDLC line discipline maxframe=%u\n";
-static char hdlc_register_ok[] __initdata =
-       KERN_INFO "N_HDLC line discipline registered.\n";
-static char hdlc_register_fail[] __initdata =
-       KERN_ERR "error registering line discipline: %d\n";
-static char hdlc_init_fail[] __initdata =
-       KERN_INFO "N_HDLC: init failure %d\n";
-
-static int __init n_hdlc_init(void)
-{
-       int status;
-
-       /* range check maxframe arg */
-       if (maxframe < 4096)
-               maxframe = 4096;
-       else if (maxframe > 65535)
-               maxframe = 65535;
-
-       printk(hdlc_banner, maxframe);
-
-       status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc);
-       if (!status)
-               printk(hdlc_register_ok);
-       else
-               printk(hdlc_register_fail, status);
-
-       if (status)
-               printk(hdlc_init_fail, status);
-       return status;
-       
-}      /* end of init_module() */
-
-static char hdlc_unregister_ok[] __exitdata =
-       KERN_INFO "N_HDLC: line discipline unregistered\n";
-static char hdlc_unregister_fail[] __exitdata =
-       KERN_ERR "N_HDLC: can't unregister line discipline (err = %d)\n";
-
-static void __exit n_hdlc_exit(void)
-{
-       /* Release tty registration of line discipline */
-       int status = tty_unregister_ldisc(N_HDLC);
-
-       if (status)
-               printk(hdlc_unregister_fail, status);
-       else
-               printk(hdlc_unregister_ok);
-}
-
-module_init(n_hdlc_init);
-module_exit(n_hdlc_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Paul Fulghum paulkf@microgate.com");
-module_param(debuglevel, int, 0);
-module_param(maxframe, int, 0);
-MODULE_ALIAS_LDISC(N_HDLC);
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
deleted file mode 100644 (file)
index 88dda0c..0000000
+++ /dev/null
@@ -1,1264 +0,0 @@
-/* r3964 linediscipline for linux
- *
- * -----------------------------------------------------------
- * Copyright by 
- * Philips Automation Projects
- * Kassel (Germany)
- * -----------------------------------------------------------
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- *
- * Author:
- * L. Haag
- *
- * $Log: n_r3964.c,v $
- * Revision 1.10  2001/03/18 13:02:24  dwmw2
- * Fix timer usage, use spinlocks properly.
- *
- * Revision 1.9  2001/03/18 12:52:14  dwmw2
- * Merge changes in 2.4.2
- *
- * Revision 1.8  2000/03/23 14:14:54  dwmw2
- * Fix race in sleeping in r3964_read()
- *
- * Revision 1.7  1999/28/08 11:41:50  dwmw2
- * Port to 2.3 kernel
- *
- * Revision 1.6  1998/09/30 00:40:40  dwmw2
- * Fixed compilation on 2.0.x kernels
- * Updated to newly registered tty-ldisc number 9
- *
- * Revision 1.5  1998/09/04 21:57:36  dwmw2
- * Signal handling bug fixes, port to 2.1.x.
- *
- * Revision 1.4  1998/04/02 20:26:59  lhaag
- * select, blocking, ...
- *
- * Revision 1.3  1998/02/12 18:58:43  root
- * fixed some memory leaks
- * calculation of checksum characters
- *
- * Revision 1.2  1998/02/07 13:03:34  root
- * ioctl read_telegram
- *
- * Revision 1.1  1998/02/06 19:21:03  root
- * Initial revision
- *
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/string.h>      /* used in new tty drivers */
-#include <linux/signal.h>      /* used in new tty drivers */
-#include <linux/ioctl.h>
-#include <linux/n_r3964.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-
-/*#define DEBUG_QUEUE*/
-
-/* Log successful handshake and protocol operations  */
-/*#define DEBUG_PROTO_S*/
-
-/* Log handshake and protocol errors: */
-/*#define DEBUG_PROTO_E*/
-
-/* Log Linediscipline operations (open, close, read, write...): */
-/*#define DEBUG_LDISC*/
-
-/* Log module and memory operations (init, cleanup; kmalloc, kfree): */
-/*#define DEBUG_MODUL*/
-
-/* Macro helpers for debug output: */
-#define TRACE(format, args...) printk("r3964: " format "\n" , ## args)
-
-#ifdef DEBUG_MODUL
-#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_M(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_PROTO_S
-#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_PS(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_PROTO_E
-#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_PE(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_LDISC
-#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_L(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_QUEUE
-#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_Q(fmt, arg...) do {} while (0)
-#endif
-static void add_tx_queue(struct r3964_info *, struct r3964_block_header *);
-static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code);
-static void put_char(struct r3964_info *pInfo, unsigned char ch);
-static void trigger_transmit(struct r3964_info *pInfo);
-static void retry_transmit(struct r3964_info *pInfo);
-static void transmit_block(struct r3964_info *pInfo);
-static void receive_char(struct r3964_info *pInfo, const unsigned char c);
-static void receive_error(struct r3964_info *pInfo, const char flag);
-static void on_timeout(unsigned long priv);
-static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg);
-static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
-               unsigned char __user * buf);
-static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
-               int error_code, struct r3964_block_header *pBlock);
-static struct r3964_message *remove_msg(struct r3964_info *pInfo,
-               struct r3964_client_info *pClient);
-static void remove_client_block(struct r3964_info *pInfo,
-               struct r3964_client_info *pClient);
-
-static int r3964_open(struct tty_struct *tty);
-static void r3964_close(struct tty_struct *tty);
-static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
-               unsigned char __user * buf, size_t nr);
-static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
-               const unsigned char *buf, size_t nr);
-static int r3964_ioctl(struct tty_struct *tty, struct file *file,
-               unsigned int cmd, unsigned long arg);
-static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old);
-static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
-               struct poll_table_struct *wait);
-static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-               char *fp, int count);
-
-static struct tty_ldisc_ops tty_ldisc_N_R3964 = {
-       .owner = THIS_MODULE,
-       .magic = TTY_LDISC_MAGIC,
-       .name = "R3964",
-       .open = r3964_open,
-       .close = r3964_close,
-       .read = r3964_read,
-       .write = r3964_write,
-       .ioctl = r3964_ioctl,
-       .set_termios = r3964_set_termios,
-       .poll = r3964_poll,
-       .receive_buf = r3964_receive_buf,
-};
-
-static void dump_block(const unsigned char *block, unsigned int length)
-{
-       unsigned int i, j;
-       char linebuf[16 * 3 + 1];
-
-       for (i = 0; i < length; i += 16) {
-               for (j = 0; (j < 16) && (j + i < length); j++) {
-                       sprintf(linebuf + 3 * j, "%02x ", block[i + j]);
-               }
-               linebuf[3 * j] = '\0';
-               TRACE_PS("%s", linebuf);
-       }
-}
-
-/*************************************************************
- * Driver initialisation
- *************************************************************/
-
-/*************************************************************
- * Module support routines
- *************************************************************/
-
-static void __exit r3964_exit(void)
-{
-       int status;
-
-       TRACE_M("cleanup_module()");
-
-       status = tty_unregister_ldisc(N_R3964);
-
-       if (status != 0) {
-               printk(KERN_ERR "r3964: error unregistering linediscipline: "
-                               "%d\n", status);
-       } else {
-               TRACE_L("linediscipline successfully unregistered");
-       }
-}
-
-static int __init r3964_init(void)
-{
-       int status;
-
-       printk("r3964: Philips r3964 Driver $Revision: 1.10 $\n");
-
-       /*
-        * Register the tty line discipline
-        */
-
-       status = tty_register_ldisc(N_R3964, &tty_ldisc_N_R3964);
-       if (status == 0) {
-               TRACE_L("line discipline %d registered", N_R3964);
-               TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags,
-                       tty_ldisc_N_R3964.num);
-               TRACE_L("open=%p", tty_ldisc_N_R3964.open);
-               TRACE_L("tty_ldisc_N_R3964 = %p", &tty_ldisc_N_R3964);
-       } else {
-               printk(KERN_ERR "r3964: error registering line discipline: "
-                               "%d\n", status);
-       }
-       return status;
-}
-
-module_init(r3964_init);
-module_exit(r3964_exit);
-
-/*************************************************************
- * Protocol implementation routines
- *************************************************************/
-
-static void add_tx_queue(struct r3964_info *pInfo,
-                        struct r3964_block_header *pHeader)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&pInfo->lock, flags);
-
-       pHeader->next = NULL;
-
-       if (pInfo->tx_last == NULL) {
-               pInfo->tx_first = pInfo->tx_last = pHeader;
-       } else {
-               pInfo->tx_last->next = pHeader;
-               pInfo->tx_last = pHeader;
-       }
-
-       spin_unlock_irqrestore(&pInfo->lock, flags);
-
-       TRACE_Q("add_tx_queue %p, length %d, tx_first = %p",
-               pHeader, pHeader->length, pInfo->tx_first);
-}
-
-static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code)
-{
-       struct r3964_block_header *pHeader;
-       unsigned long flags;
-#ifdef DEBUG_QUEUE
-       struct r3964_block_header *pDump;
-#endif
-
-       pHeader = pInfo->tx_first;
-
-       if (pHeader == NULL)
-               return;
-
-#ifdef DEBUG_QUEUE
-       printk("r3964: remove_from_tx_queue: %p, length %u - ",
-               pHeader, pHeader->length);
-       for (pDump = pHeader; pDump; pDump = pDump->next)
-               printk("%p ", pDump);
-       printk("\n");
-#endif
-
-       if (pHeader->owner) {
-               if (error_code) {
-                       add_msg(pHeader->owner, R3964_MSG_ACK, 0,
-                               error_code, NULL);
-               } else {
-                       add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length,
-                               error_code, NULL);
-               }
-               wake_up_interruptible(&pInfo->read_wait);
-       }
-
-       spin_lock_irqsave(&pInfo->lock, flags);
-
-       pInfo->tx_first = pHeader->next;
-       if (pInfo->tx_first == NULL) {
-               pInfo->tx_last = NULL;
-       }
-
-       spin_unlock_irqrestore(&pInfo->lock, flags);
-
-       kfree(pHeader);
-       TRACE_M("remove_from_tx_queue - kfree %p", pHeader);
-
-       TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p",
-               pInfo->tx_first, pInfo->tx_last);
-}
-
-static void add_rx_queue(struct r3964_info *pInfo,
-                        struct r3964_block_header *pHeader)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&pInfo->lock, flags);
-
-       pHeader->next = NULL;
-
-       if (pInfo->rx_last == NULL) {
-               pInfo->rx_first = pInfo->rx_last = pHeader;
-       } else {
-               pInfo->rx_last->next = pHeader;
-               pInfo->rx_last = pHeader;
-       }
-       pInfo->blocks_in_rx_queue++;
-
-       spin_unlock_irqrestore(&pInfo->lock, flags);
-
-       TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d",
-               pHeader, pHeader->length,
-               pInfo->rx_first, pInfo->blocks_in_rx_queue);
-}
-
-static void remove_from_rx_queue(struct r3964_info *pInfo,
-                                struct r3964_block_header *pHeader)
-{
-       unsigned long flags;
-       struct r3964_block_header *pFind;
-
-       if (pHeader == NULL)
-               return;
-
-       TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
-               pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
-       TRACE_Q("remove_from_rx_queue: %p, length %u",
-               pHeader, pHeader->length);
-
-       spin_lock_irqsave(&pInfo->lock, flags);
-
-       if (pInfo->rx_first == pHeader) {
-               /* Remove the first block in the linked list: */
-               pInfo->rx_first = pHeader->next;
-
-               if (pInfo->rx_first == NULL) {
-                       pInfo->rx_last = NULL;
-               }
-               pInfo->blocks_in_rx_queue--;
-       } else {
-               /* Find block to remove: */
-               for (pFind = pInfo->rx_first; pFind; pFind = pFind->next) {
-                       if (pFind->next == pHeader) {
-                               /* Got it. */
-                               pFind->next = pHeader->next;
-                               pInfo->blocks_in_rx_queue--;
-                               if (pFind->next == NULL) {
-                                       /* Oh, removed the last one! */
-                                       pInfo->rx_last = pFind;
-                               }
-                               break;
-                       }
-               }
-       }
-
-       spin_unlock_irqrestore(&pInfo->lock, flags);
-
-       kfree(pHeader);
-       TRACE_M("remove_from_rx_queue - kfree %p", pHeader);
-
-       TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
-               pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
-}
-
-static void put_char(struct r3964_info *pInfo, unsigned char ch)
-{
-       struct tty_struct *tty = pInfo->tty;
-       /* FIXME: put_char should not be called from an IRQ */
-       tty_put_char(tty, ch);
-       pInfo->bcc ^= ch;
-}
-
-static void flush(struct r3964_info *pInfo)
-{
-       struct tty_struct *tty = pInfo->tty;
-
-       if (tty == NULL || tty->ops->flush_chars == NULL)
-               return;
-       tty->ops->flush_chars(tty);
-}
-
-static void trigger_transmit(struct r3964_info *pInfo)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&pInfo->lock, flags);
-
-       if ((pInfo->state == R3964_IDLE) && (pInfo->tx_first != NULL)) {
-               pInfo->state = R3964_TX_REQUEST;
-               pInfo->nRetry = 0;
-               pInfo->flags &= ~R3964_ERROR;
-               mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
-
-               spin_unlock_irqrestore(&pInfo->lock, flags);
-
-               TRACE_PS("trigger_transmit - sent STX");
-
-               put_char(pInfo, STX);
-               flush(pInfo);
-
-               pInfo->bcc = 0;
-       } else {
-               spin_unlock_irqrestore(&pInfo->lock, flags);
-       }
-}
-
-static void retry_transmit(struct r3964_info *pInfo)
-{
-       if (pInfo->nRetry < R3964_MAX_RETRIES) {
-               TRACE_PE("transmission failed. Retry #%d", pInfo->nRetry);
-               pInfo->bcc = 0;
-               put_char(pInfo, STX);
-               flush(pInfo);
-               pInfo->state = R3964_TX_REQUEST;
-               pInfo->nRetry++;
-               mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
-       } else {
-               TRACE_PE("transmission failed after %d retries",
-                        R3964_MAX_RETRIES);
-
-               remove_from_tx_queue(pInfo, R3964_TX_FAIL);
-
-               put_char(pInfo, NAK);
-               flush(pInfo);
-               pInfo->state = R3964_IDLE;
-
-               trigger_transmit(pInfo);
-       }
-}
-
-static void transmit_block(struct r3964_info *pInfo)
-{
-       struct tty_struct *tty = pInfo->tty;
-       struct r3964_block_header *pBlock = pInfo->tx_first;
-       int room = 0;
-
-       if (tty == NULL || pBlock == NULL) {
-               return;
-       }
-
-       room = tty_write_room(tty);
-
-       TRACE_PS("transmit_block %p, room %d, length %d",
-                pBlock, room, pBlock->length);
-
-       while (pInfo->tx_position < pBlock->length) {
-               if (room < 2)
-                       break;
-
-               if (pBlock->data[pInfo->tx_position] == DLE) {
-                       /* send additional DLE char: */
-                       put_char(pInfo, DLE);
-               }
-               put_char(pInfo, pBlock->data[pInfo->tx_position++]);
-
-               room--;
-       }
-
-       if ((pInfo->tx_position == pBlock->length) && (room >= 3)) {
-               put_char(pInfo, DLE);
-               put_char(pInfo, ETX);
-               if (pInfo->flags & R3964_BCC) {
-                       put_char(pInfo, pInfo->bcc);
-               }
-               pInfo->state = R3964_WAIT_FOR_TX_ACK;
-               mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
-       }
-       flush(pInfo);
-}
-
-static void on_receive_block(struct r3964_info *pInfo)
-{
-       unsigned int length;
-       struct r3964_client_info *pClient;
-       struct r3964_block_header *pBlock;
-
-       length = pInfo->rx_position;
-
-       /* compare byte checksum characters: */
-       if (pInfo->flags & R3964_BCC) {
-               if (pInfo->bcc != pInfo->last_rx) {
-                       TRACE_PE("checksum error - got %x but expected %x",
-                                pInfo->last_rx, pInfo->bcc);
-                       pInfo->flags |= R3964_CHECKSUM;
-               }
-       }
-
-       /* check for errors (parity, overrun,...): */
-       if (pInfo->flags & R3964_ERROR) {
-               TRACE_PE("on_receive_block - transmission failed error %x",
-                        pInfo->flags & R3964_ERROR);
-
-               put_char(pInfo, NAK);
-               flush(pInfo);
-               if (pInfo->nRetry < R3964_MAX_RETRIES) {
-                       pInfo->state = R3964_WAIT_FOR_RX_REPEAT;
-                       pInfo->nRetry++;
-                       mod_timer(&pInfo->tmr, jiffies + R3964_TO_RX_PANIC);
-               } else {
-                       TRACE_PE("on_receive_block - failed after max retries");
-                       pInfo->state = R3964_IDLE;
-               }
-               return;
-       }
-
-       /* received block; submit DLE: */
-       put_char(pInfo, DLE);
-       flush(pInfo);
-       del_timer_sync(&pInfo->tmr);
-       TRACE_PS(" rx success: got %d chars", length);
-
-       /* prepare struct r3964_block_header: */
-       pBlock = kmalloc(length + sizeof(struct r3964_block_header),
-                       GFP_KERNEL);
-       TRACE_M("on_receive_block - kmalloc %p", pBlock);
-
-       if (pBlock == NULL)
-               return;
-
-       pBlock->length = length;
-       pBlock->data = ((unsigned char *)pBlock) +
-                       sizeof(struct r3964_block_header);
-       pBlock->locks = 0;
-       pBlock->next = NULL;
-       pBlock->owner = NULL;
-
-       memcpy(pBlock->data, pInfo->rx_buf, length);
-
-       /* queue block into rx_queue: */
-       add_rx_queue(pInfo, pBlock);
-
-       /* notify attached client processes: */
-       for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
-               if (pClient->sig_flags & R3964_SIG_DATA) {
-                       add_msg(pClient, R3964_MSG_DATA, length, R3964_OK,
-                               pBlock);
-               }
-       }
-       wake_up_interruptible(&pInfo->read_wait);
-
-       pInfo->state = R3964_IDLE;
-
-       trigger_transmit(pInfo);
-}
-
-static void receive_char(struct r3964_info *pInfo, const unsigned char c)
-{
-       switch (pInfo->state) {
-       case R3964_TX_REQUEST:
-               if (c == DLE) {
-                       TRACE_PS("TX_REQUEST - got DLE");
-
-                       pInfo->state = R3964_TRANSMITTING;
-                       pInfo->tx_position = 0;
-
-                       transmit_block(pInfo);
-               } else if (c == STX) {
-                       if (pInfo->nRetry == 0) {
-                               TRACE_PE("TX_REQUEST - init conflict");
-                               if (pInfo->priority == R3964_SLAVE) {
-                                       goto start_receiving;
-                               }
-                       } else {
-                               TRACE_PE("TX_REQUEST - secondary init "
-                                       "conflict!? Switching to SLAVE mode "
-                                       "for next rx.");
-                               goto start_receiving;
-                       }
-               } else {
-                       TRACE_PE("TX_REQUEST - char != DLE: %x", c);
-                       retry_transmit(pInfo);
-               }
-               break;
-       case R3964_TRANSMITTING:
-               if (c == NAK) {
-                       TRACE_PE("TRANSMITTING - got NAK");
-                       retry_transmit(pInfo);
-               } else {
-                       TRACE_PE("TRANSMITTING - got invalid char");
-
-                       pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY;
-                       mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
-               }
-               break;
-       case R3964_WAIT_FOR_TX_ACK:
-               if (c == DLE) {
-                       TRACE_PS("WAIT_FOR_TX_ACK - got DLE");
-                       remove_from_tx_queue(pInfo, R3964_OK);
-
-                       pInfo->state = R3964_IDLE;
-                       trigger_transmit(pInfo);
-               } else {
-                       retry_transmit(pInfo);
-               }
-               break;
-       case R3964_WAIT_FOR_RX_REPEAT:
-               /* FALLTHROUGH */
-       case R3964_IDLE:
-               if (c == STX) {
-                       /* Prevent rx_queue from overflow: */
-                       if (pInfo->blocks_in_rx_queue >=
-                           R3964_MAX_BLOCKS_IN_RX_QUEUE) {
-                               TRACE_PE("IDLE - got STX but no space in "
-                                               "rx_queue!");
-                               pInfo->state = R3964_WAIT_FOR_RX_BUF;
-                               mod_timer(&pInfo->tmr,
-                                         jiffies + R3964_TO_NO_BUF);
-                               break;
-                       }
-start_receiving:
-                       /* Ok, start receiving: */
-                       TRACE_PS("IDLE - got STX");
-                       pInfo->rx_position = 0;
-                       pInfo->last_rx = 0;
-                       pInfo->flags &= ~R3964_ERROR;
-                       pInfo->state = R3964_RECEIVING;
-                       mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
-                       pInfo->nRetry = 0;
-                       put_char(pInfo, DLE);
-                       flush(pInfo);
-                       pInfo->bcc = 0;
-               }
-               break;
-       case R3964_RECEIVING:
-               if (pInfo->rx_position < RX_BUF_SIZE) {
-                       pInfo->bcc ^= c;
-
-                       if (c == DLE) {
-                               if (pInfo->last_rx == DLE) {
-                                       pInfo->last_rx = 0;
-                                       goto char_to_buf;
-                               }
-                               pInfo->last_rx = DLE;
-                               break;
-                       } else if ((c == ETX) && (pInfo->last_rx == DLE)) {
-                               if (pInfo->flags & R3964_BCC) {
-                                       pInfo->state = R3964_WAIT_FOR_BCC;
-                                       mod_timer(&pInfo->tmr,
-                                                 jiffies + R3964_TO_ZVZ);
-                               } else {
-                                       on_receive_block(pInfo);
-                               }
-                       } else {
-                               pInfo->last_rx = c;
-char_to_buf:
-                               pInfo->rx_buf[pInfo->rx_position++] = c;
-                               mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
-                       }
-               }
-               /* else: overflow-msg? BUF_SIZE>MTU; should not happen? */
-               break;
-       case R3964_WAIT_FOR_BCC:
-               pInfo->last_rx = c;
-               on_receive_block(pInfo);
-               break;
-       }
-}
-
-static void receive_error(struct r3964_info *pInfo, const char flag)
-{
-       switch (flag) {
-       case TTY_NORMAL:
-               break;
-       case TTY_BREAK:
-               TRACE_PE("received break");
-               pInfo->flags |= R3964_BREAK;
-               break;
-       case TTY_PARITY:
-               TRACE_PE("parity error");
-               pInfo->flags |= R3964_PARITY;
-               break;
-       case TTY_FRAME:
-               TRACE_PE("frame error");
-               pInfo->flags |= R3964_FRAME;
-               break;
-       case TTY_OVERRUN:
-               TRACE_PE("frame overrun");
-               pInfo->flags |= R3964_OVERRUN;
-               break;
-       default:
-               TRACE_PE("receive_error - unknown flag %d", flag);
-               pInfo->flags |= R3964_UNKNOWN;
-               break;
-       }
-}
-
-static void on_timeout(unsigned long priv)
-{
-       struct r3964_info *pInfo = (void *)priv;
-
-       switch (pInfo->state) {
-       case R3964_TX_REQUEST:
-               TRACE_PE("TX_REQUEST - timeout");
-               retry_transmit(pInfo);
-               break;
-       case R3964_WAIT_ZVZ_BEFORE_TX_RETRY:
-               put_char(pInfo, NAK);
-               flush(pInfo);
-               retry_transmit(pInfo);
-               break;
-       case R3964_WAIT_FOR_TX_ACK:
-               TRACE_PE("WAIT_FOR_TX_ACK - timeout");
-               retry_transmit(pInfo);
-               break;
-       case R3964_WAIT_FOR_RX_BUF:
-               TRACE_PE("WAIT_FOR_RX_BUF - timeout");
-               put_char(pInfo, NAK);
-               flush(pInfo);
-               pInfo->state = R3964_IDLE;
-               break;
-       case R3964_RECEIVING:
-               TRACE_PE("RECEIVING - timeout after %d chars",
-                        pInfo->rx_position);
-               put_char(pInfo, NAK);
-               flush(pInfo);
-               pInfo->state = R3964_IDLE;
-               break;
-       case R3964_WAIT_FOR_RX_REPEAT:
-               TRACE_PE("WAIT_FOR_RX_REPEAT - timeout");
-               pInfo->state = R3964_IDLE;
-               break;
-       case R3964_WAIT_FOR_BCC:
-               TRACE_PE("WAIT_FOR_BCC - timeout");
-               put_char(pInfo, NAK);
-               flush(pInfo);
-               pInfo->state = R3964_IDLE;
-               break;
-       }
-}
-
-static struct r3964_client_info *findClient(struct r3964_info *pInfo,
-               struct pid *pid)
-{
-       struct r3964_client_info *pClient;
-
-       for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
-               if (pClient->pid == pid) {
-                       return pClient;
-               }
-       }
-       return NULL;
-}
-
-static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg)
-{
-       struct r3964_client_info *pClient;
-       struct r3964_client_info **ppClient;
-       struct r3964_message *pMsg;
-
-       if ((arg & R3964_SIG_ALL) == 0) {
-               /* Remove client from client list */
-               for (ppClient = &pInfo->firstClient; *ppClient;
-                    ppClient = &(*ppClient)->next) {
-                       pClient = *ppClient;
-
-                       if (pClient->pid == pid) {
-                               TRACE_PS("removing client %d from client list",
-                                        pid_nr(pid));
-                               *ppClient = pClient->next;
-                               while (pClient->msg_count) {
-                                       pMsg = remove_msg(pInfo, pClient);
-                                       if (pMsg) {
-                                               kfree(pMsg);
-                                               TRACE_M("enable_signals - msg "
-                                                       "kfree %p", pMsg);
-                                       }
-                               }
-                               put_pid(pClient->pid);
-                               kfree(pClient);
-                               TRACE_M("enable_signals - kfree %p", pClient);
-                               return 0;
-                       }
-               }
-               return -EINVAL;
-       } else {
-               pClient = findClient(pInfo, pid);
-               if (pClient) {
-                       /* update signal options */
-                       pClient->sig_flags = arg;
-               } else {
-                       /* add client to client list */
-                       pClient = kmalloc(sizeof(struct r3964_client_info),
-                                       GFP_KERNEL);
-                       TRACE_M("enable_signals - kmalloc %p", pClient);
-                       if (pClient == NULL)
-                               return -ENOMEM;
-
-                       TRACE_PS("add client %d to client list", pid_nr(pid));
-                       spin_lock_init(&pClient->lock);
-                       pClient->sig_flags = arg;
-                       pClient->pid = get_pid(pid);
-                       pClient->next = pInfo->firstClient;
-                       pClient->first_msg = NULL;
-                       pClient->last_msg = NULL;
-                       pClient->next_block_to_read = NULL;
-                       pClient->msg_count = 0;
-                       pInfo->firstClient = pClient;
-               }
-       }
-
-       return 0;
-}
-
-static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
-                        unsigned char __user * buf)
-{
-       struct r3964_client_info *pClient;
-       struct r3964_block_header *block;
-
-       if (!buf) {
-               return -EINVAL;
-       }
-
-       pClient = findClient(pInfo, pid);
-       if (pClient == NULL) {
-               return -EINVAL;
-       }
-
-       block = pClient->next_block_to_read;
-       if (!block) {
-               return 0;
-       } else {
-               if (copy_to_user(buf, block->data, block->length))
-                       return -EFAULT;
-
-               remove_client_block(pInfo, pClient);
-               return block->length;
-       }
-
-       return -EINVAL;
-}
-
-static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
-               int error_code, struct r3964_block_header *pBlock)
-{
-       struct r3964_message *pMsg;
-       unsigned long flags;
-
-       if (pClient->msg_count < R3964_MAX_MSG_COUNT - 1) {
-queue_the_message:
-
-               pMsg = kmalloc(sizeof(struct r3964_message),
-                               error_code ? GFP_ATOMIC : GFP_KERNEL);
-               TRACE_M("add_msg - kmalloc %p", pMsg);
-               if (pMsg == NULL) {
-                       return;
-               }
-
-               spin_lock_irqsave(&pClient->lock, flags);
-
-               pMsg->msg_id = msg_id;
-               pMsg->arg = arg;
-               pMsg->error_code = error_code;
-               pMsg->block = pBlock;
-               pMsg->next = NULL;
-
-               if (pClient->last_msg == NULL) {
-                       pClient->first_msg = pClient->last_msg = pMsg;
-               } else {
-                       pClient->last_msg->next = pMsg;
-                       pClient->last_msg = pMsg;
-               }
-
-               pClient->msg_count++;
-
-               if (pBlock != NULL) {
-                       pBlock->locks++;
-               }
-               spin_unlock_irqrestore(&pClient->lock, flags);
-       } else {
-               if ((pClient->last_msg->msg_id == R3964_MSG_ACK)
-                   && (pClient->last_msg->error_code == R3964_OVERFLOW)) {
-                       pClient->last_msg->arg++;
-                       TRACE_PE("add_msg - inc prev OVERFLOW-msg");
-               } else {
-                       msg_id = R3964_MSG_ACK;
-                       arg = 0;
-                       error_code = R3964_OVERFLOW;
-                       pBlock = NULL;
-                       TRACE_PE("add_msg - queue OVERFLOW-msg");
-                       goto queue_the_message;
-               }
-       }
-       /* Send SIGIO signal to client process: */
-       if (pClient->sig_flags & R3964_USE_SIGIO) {
-               kill_pid(pClient->pid, SIGIO, 1);
-       }
-}
-
-static struct r3964_message *remove_msg(struct r3964_info *pInfo,
-                                       struct r3964_client_info *pClient)
-{
-       struct r3964_message *pMsg = NULL;
-       unsigned long flags;
-
-       if (pClient->first_msg) {
-               spin_lock_irqsave(&pClient->lock, flags);
-
-               pMsg = pClient->first_msg;
-               pClient->first_msg = pMsg->next;
-               if (pClient->first_msg == NULL) {
-                       pClient->last_msg = NULL;
-               }
-
-               pClient->msg_count--;
-               if (pMsg->block) {
-                       remove_client_block(pInfo, pClient);
-                       pClient->next_block_to_read = pMsg->block;
-               }
-               spin_unlock_irqrestore(&pClient->lock, flags);
-       }
-       return pMsg;
-}
-
-static void remove_client_block(struct r3964_info *pInfo,
-                               struct r3964_client_info *pClient)
-{
-       struct r3964_block_header *block;
-
-       TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid));
-
-       block = pClient->next_block_to_read;
-       if (block) {
-               block->locks--;
-               if (block->locks == 0) {
-                       remove_from_rx_queue(pInfo, block);
-               }
-       }
-       pClient->next_block_to_read = NULL;
-}
-
-/*************************************************************
- * Line discipline routines
- *************************************************************/
-
-static int r3964_open(struct tty_struct *tty)
-{
-       struct r3964_info *pInfo;
-
-       TRACE_L("open");
-       TRACE_L("tty=%p, PID=%d, disc_data=%p",
-               tty, current->pid, tty->disc_data);
-
-       pInfo = kmalloc(sizeof(struct r3964_info), GFP_KERNEL);
-       TRACE_M("r3964_open - info kmalloc %p", pInfo);
-
-       if (!pInfo) {
-               printk(KERN_ERR "r3964: failed to alloc info structure\n");
-               return -ENOMEM;
-       }
-
-       pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL);
-       TRACE_M("r3964_open - rx_buf kmalloc %p", pInfo->rx_buf);
-
-       if (!pInfo->rx_buf) {
-               printk(KERN_ERR "r3964: failed to alloc receive buffer\n");
-               kfree(pInfo);
-               TRACE_M("r3964_open - info kfree %p", pInfo);
-               return -ENOMEM;
-       }
-
-       pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL);
-       TRACE_M("r3964_open - tx_buf kmalloc %p", pInfo->tx_buf);
-
-       if (!pInfo->tx_buf) {
-               printk(KERN_ERR "r3964: failed to alloc transmit buffer\n");
-               kfree(pInfo->rx_buf);
-               TRACE_M("r3964_open - rx_buf kfree %p", pInfo->rx_buf);
-               kfree(pInfo);
-               TRACE_M("r3964_open - info kfree %p", pInfo);
-               return -ENOMEM;
-       }
-
-       spin_lock_init(&pInfo->lock);
-       pInfo->tty = tty;
-       init_waitqueue_head(&pInfo->read_wait);
-       pInfo->priority = R3964_MASTER;
-       pInfo->rx_first = pInfo->rx_last = NULL;
-       pInfo->tx_first = pInfo->tx_last = NULL;
-       pInfo->rx_position = 0;
-       pInfo->tx_position = 0;
-       pInfo->last_rx = 0;
-       pInfo->blocks_in_rx_queue = 0;
-       pInfo->firstClient = NULL;
-       pInfo->state = R3964_IDLE;
-       pInfo->flags = R3964_DEBUG;
-       pInfo->nRetry = 0;
-
-       tty->disc_data = pInfo;
-       tty->receive_room = 65536;
-
-       setup_timer(&pInfo->tmr, on_timeout, (unsigned long)pInfo);
-
-       return 0;
-}
-
-static void r3964_close(struct tty_struct *tty)
-{
-       struct r3964_info *pInfo = tty->disc_data;
-       struct r3964_client_info *pClient, *pNext;
-       struct r3964_message *pMsg;
-       struct r3964_block_header *pHeader, *pNextHeader;
-       unsigned long flags;
-
-       TRACE_L("close");
-
-       /*
-        * Make sure that our task queue isn't activated.  If it
-        * is, take it out of the linked list.
-        */
-       del_timer_sync(&pInfo->tmr);
-
-       /* Remove client-structs and message queues: */
-       pClient = pInfo->firstClient;
-       while (pClient) {
-               pNext = pClient->next;
-               while (pClient->msg_count) {
-                       pMsg = remove_msg(pInfo, pClient);
-                       if (pMsg) {
-                               kfree(pMsg);
-                               TRACE_M("r3964_close - msg kfree %p", pMsg);
-                       }
-               }
-               put_pid(pClient->pid);
-               kfree(pClient);
-               TRACE_M("r3964_close - client kfree %p", pClient);
-               pClient = pNext;
-       }
-       /* Remove jobs from tx_queue: */
-       spin_lock_irqsave(&pInfo->lock, flags);
-       pHeader = pInfo->tx_first;
-       pInfo->tx_first = pInfo->tx_last = NULL;
-       spin_unlock_irqrestore(&pInfo->lock, flags);
-
-       while (pHeader) {
-               pNextHeader = pHeader->next;
-               kfree(pHeader);
-               pHeader = pNextHeader;
-       }
-
-       /* Free buffers: */
-       wake_up_interruptible(&pInfo->read_wait);
-       kfree(pInfo->rx_buf);
-       TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf);
-       kfree(pInfo->tx_buf);
-       TRACE_M("r3964_close - tx_buf kfree %p", pInfo->tx_buf);
-       kfree(pInfo);
-       TRACE_M("r3964_close - info kfree %p", pInfo);
-}
-
-static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
-                         unsigned char __user * buf, size_t nr)
-{
-       struct r3964_info *pInfo = tty->disc_data;
-       struct r3964_client_info *pClient;
-       struct r3964_message *pMsg;
-       struct r3964_client_message theMsg;
-       int ret;
-
-       TRACE_L("read()");
-
-       tty_lock();
-
-       pClient = findClient(pInfo, task_pid(current));
-       if (pClient) {
-               pMsg = remove_msg(pInfo, pClient);
-               if (pMsg == NULL) {
-                       /* no messages available. */
-                       if (file->f_flags & O_NONBLOCK) {
-                               ret = -EAGAIN;
-                               goto unlock;
-                       }
-                       /* block until there is a message: */
-                       wait_event_interruptible_tty(pInfo->read_wait,
-                                       (pMsg = remove_msg(pInfo, pClient)));
-               }
-
-               /* If we still haven't got a message, we must have been signalled */
-
-               if (!pMsg) {
-                       ret = -EINTR;
-                       goto unlock;
-               }
-
-               /* deliver msg to client process: */
-               theMsg.msg_id = pMsg->msg_id;
-               theMsg.arg = pMsg->arg;
-               theMsg.error_code = pMsg->error_code;
-               ret = sizeof(struct r3964_client_message);
-
-               kfree(pMsg);
-               TRACE_M("r3964_read - msg kfree %p", pMsg);
-
-               if (copy_to_user(buf, &theMsg, ret)) {
-                       ret = -EFAULT;
-                       goto unlock;
-               }
-
-               TRACE_PS("read - return %d", ret);
-               goto unlock;
-       }
-       ret = -EPERM;
-unlock:
-       tty_unlock();
-       return ret;
-}
-
-static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
-                          const unsigned char *data, size_t count)
-{
-       struct r3964_info *pInfo = tty->disc_data;
-       struct r3964_block_header *pHeader;
-       struct r3964_client_info *pClient;
-       unsigned char *new_data;
-
-       TRACE_L("write request, %d characters", count);
-/* 
- * Verify the pointers 
- */
-
-       if (!pInfo)
-               return -EIO;
-
-/*
- * Ensure that the caller does not wish to send too much.
- */
-       if (count > R3964_MTU) {
-               if (pInfo->flags & R3964_DEBUG) {
-                       TRACE_L(KERN_WARNING "r3964_write: truncating user "
-                               "packet from %u to mtu %d", count, R3964_MTU);
-               }
-               count = R3964_MTU;
-       }
-/*
- * Allocate a buffer for the data and copy it from the buffer with header prepended
- */
-       new_data = kmalloc(count + sizeof(struct r3964_block_header),
-                       GFP_KERNEL);
-       TRACE_M("r3964_write - kmalloc %p", new_data);
-       if (new_data == NULL) {
-               if (pInfo->flags & R3964_DEBUG) {
-                       printk(KERN_ERR "r3964_write: no memory\n");
-               }
-               return -ENOSPC;
-       }
-
-       pHeader = (struct r3964_block_header *)new_data;
-       pHeader->data = new_data + sizeof(struct r3964_block_header);
-       pHeader->length = count;
-       pHeader->locks = 0;
-       pHeader->owner = NULL;
-
-       tty_lock();
-
-       pClient = findClient(pInfo, task_pid(current));
-       if (pClient) {
-               pHeader->owner = pClient;
-       }
-
-       memcpy(pHeader->data, data, count);     /* We already verified this */
-
-       if (pInfo->flags & R3964_DEBUG) {
-               dump_block(pHeader->data, count);
-       }
-
-/*
- * Add buffer to transmit-queue:
- */
-       add_tx_queue(pInfo, pHeader);
-       trigger_transmit(pInfo);
-
-       tty_unlock();
-
-       return 0;
-}
-
-static int r3964_ioctl(struct tty_struct *tty, struct file *file,
-               unsigned int cmd, unsigned long arg)
-{
-       struct r3964_info *pInfo = tty->disc_data;
-       if (pInfo == NULL)
-               return -EINVAL;
-       switch (cmd) {
-       case R3964_ENABLE_SIGNALS:
-               return enable_signals(pInfo, task_pid(current), arg);
-       case R3964_SETPRIORITY:
-               if (arg < R3964_MASTER || arg > R3964_SLAVE)
-                       return -EINVAL;
-               pInfo->priority = arg & 0xff;
-               return 0;
-       case R3964_USE_BCC:
-               if (arg)
-                       pInfo->flags |= R3964_BCC;
-               else
-                       pInfo->flags &= ~R3964_BCC;
-               return 0;
-       case R3964_READ_TELEGRAM:
-               return read_telegram(pInfo, task_pid(current),
-                               (unsigned char __user *)arg);
-       default:
-               return -ENOIOCTLCMD;
-       }
-}
-
-static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old)
-{
-       TRACE_L("set_termios");
-}
-
-/* Called without the kernel lock held - fine */
-static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
-                       struct poll_table_struct *wait)
-{
-       struct r3964_info *pInfo = tty->disc_data;
-       struct r3964_client_info *pClient;
-       struct r3964_message *pMsg = NULL;
-       unsigned long flags;
-       int result = POLLOUT;
-
-       TRACE_L("POLL");
-
-       pClient = findClient(pInfo, task_pid(current));
-       if (pClient) {
-               poll_wait(file, &pInfo->read_wait, wait);
-               spin_lock_irqsave(&pInfo->lock, flags);
-               pMsg = pClient->first_msg;
-               spin_unlock_irqrestore(&pInfo->lock, flags);
-               if (pMsg)
-                       result |= POLLIN | POLLRDNORM;
-       } else {
-               result = -EINVAL;
-       }
-       return result;
-}
-
-static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-                       char *fp, int count)
-{
-       struct r3964_info *pInfo = tty->disc_data;
-       const unsigned char *p;
-       char *f, flags = 0;
-       int i;
-
-       for (i = count, p = cp, f = fp; i; i--, p++) {
-               if (f)
-                       flags = *f++;
-               if (flags == TTY_NORMAL) {
-                       receive_char(pInfo, *p);
-               } else {
-                       receive_error(pInfo, flags);
-               }
-
-       }
-}
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_LDISC(N_R3964);
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
deleted file mode 100644 (file)
index 428f4fe..0000000
+++ /dev/null
@@ -1,2121 +0,0 @@
-/*
- * n_tty.c --- implements the N_TTY line discipline.
- *
- * This code used to be in tty_io.c, but things are getting hairy
- * enough that it made sense to split things off.  (The N_TTY
- * processing has changed so much that it's hardly recognizable,
- * anyway...)
- *
- * Note that the open routine for N_TTY is guaranteed never to return
- * an error.  This is because Linux will fall back to setting a line
- * to N_TTY if it can not switch to any other line discipline.
- *
- * Written by Theodore Ts'o, Copyright 1994.
- *
- * This file also contains code originally written by Linus Torvalds,
- * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994.
- *
- * This file may be redistributed under the terms of the GNU General Public
- * License.
- *
- * Reduced memory usage for older ARM systems  - Russell King.
- *
- * 2000/01/20   Fixed SMP locking on put_tty_queue using bits of
- *             the patch by Andrew J. Kroll <ag784@freenet.buffalo.edu>
- *             who actually finally proved there really was a race.
- *
- * 2002/03/18   Implemented n_tty_wakeup to send SIGIO POLL_OUTs to
- *             waiting writing processes-Sapan Bhatia <sapan@corewars.org>.
- *             Also fixed a bug in BLOCKING mode where n_tty_write returns
- *             EAGAIN
- */
-
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/timer.h>
-#include <linux/ctype.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/bitops.h>
-#include <linux/audit.h>
-#include <linux/file.h>
-#include <linux/uaccess.h>
-#include <linux/module.h>
-
-#include <asm/system.h>
-
-/* number of characters left in xmit buffer before select has we have room */
-#define WAKEUP_CHARS 256
-
-/*
- * This defines the low- and high-watermarks for throttling and
- * unthrottling the TTY driver.  These watermarks are used for
- * controlling the space in the read buffer.
- */
-#define TTY_THRESHOLD_THROTTLE         128 /* now based on remaining room */
-#define TTY_THRESHOLD_UNTHROTTLE       128
-
-/*
- * Special byte codes used in the echo buffer to represent operations
- * or special handling of characters.  Bytes in the echo buffer that
- * are not part of such special blocks are treated as normal character
- * codes.
- */
-#define ECHO_OP_START 0xff
-#define ECHO_OP_MOVE_BACK_COL 0x80
-#define ECHO_OP_SET_CANON_COL 0x81
-#define ECHO_OP_ERASE_TAB 0x82
-
-static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
-                              unsigned char __user *ptr)
-{
-       tty_audit_add_data(tty, &x, 1);
-       return put_user(x, ptr);
-}
-
-/**
- *     n_tty_set__room -       receive space
- *     @tty: terminal
- *
- *     Called by the driver to find out how much data it is
- *     permitted to feed to the line discipline without any being lost
- *     and thus to manage flow control. Not serialized. Answers for the
- *     "instant".
- */
-
-static void n_tty_set_room(struct tty_struct *tty)
-{
-       /* tty->read_cnt is not read locked ? */
-       int     left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
-
-       /*
-        * If we are doing input canonicalization, and there are no
-        * pending newlines, let characters through without limit, so
-        * that erase characters will be handled.  Other excess
-        * characters will be beeped.
-        */
-       if (left <= 0)
-               left = tty->icanon && !tty->canon_data;
-       tty->receive_room = left;
-}
-
-static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
-{
-       if (tty->read_cnt < N_TTY_BUF_SIZE) {
-               tty->read_buf[tty->read_head] = c;
-               tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);
-               tty->read_cnt++;
-       }
-}
-
-/**
- *     put_tty_queue           -       add character to tty
- *     @c: character
- *     @tty: tty device
- *
- *     Add a character to the tty read_buf queue. This is done under the
- *     read_lock to serialize character addition and also to protect us
- *     against parallel reads or flushes
- */
-
-static void put_tty_queue(unsigned char c, struct tty_struct *tty)
-{
-       unsigned long flags;
-       /*
-        *      The problem of stomping on the buffers ends here.
-        *      Why didn't anyone see this one coming? --AJK
-       */
-       spin_lock_irqsave(&tty->read_lock, flags);
-       put_tty_queue_nolock(c, tty);
-       spin_unlock_irqrestore(&tty->read_lock, flags);
-}
-
-/**
- *     check_unthrottle        -       allow new receive data
- *     @tty; tty device
- *
- *     Check whether to call the driver unthrottle functions
- *
- *     Can sleep, may be called under the atomic_read_lock mutex but
- *     this is not guaranteed.
- */
-static void check_unthrottle(struct tty_struct *tty)
-{
-       if (tty->count)
-               tty_unthrottle(tty);
-}
-
-/**
- *     reset_buffer_flags      -       reset buffer state
- *     @tty: terminal to reset
- *
- *     Reset the read buffer counters, clear the flags,
- *     and make sure the driver is unthrottled. Called
- *     from n_tty_open() and n_tty_flush_buffer().
- *
- *     Locking: tty_read_lock for read fields.
- */
-
-static void reset_buffer_flags(struct tty_struct *tty)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&tty->read_lock, flags);
-       tty->read_head = tty->read_tail = tty->read_cnt = 0;
-       spin_unlock_irqrestore(&tty->read_lock, flags);
-
-       mutex_lock(&tty->echo_lock);
-       tty->echo_pos = tty->echo_cnt = tty->echo_overrun = 0;
-       mutex_unlock(&tty->echo_lock);
-
-       tty->canon_head = tty->canon_data = tty->erasing = 0;
-       memset(&tty->read_flags, 0, sizeof tty->read_flags);
-       n_tty_set_room(tty);
-       check_unthrottle(tty);
-}
-
-/**
- *     n_tty_flush_buffer      -       clean input queue
- *     @tty:   terminal device
- *
- *     Flush the input buffer. Called when the line discipline is
- *     being closed, when the tty layer wants the buffer flushed (eg
- *     at hangup) or when the N_TTY line discipline internally has to
- *     clean the pending queue (for example some signals).
- *
- *     Locking: ctrl_lock, read_lock.
- */
-
-static void n_tty_flush_buffer(struct tty_struct *tty)
-{
-       unsigned long flags;
-       /* clear everything and unthrottle the driver */
-       reset_buffer_flags(tty);
-
-       if (!tty->link)
-               return;
-
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       if (tty->link->packet) {
-               tty->ctrl_status |= TIOCPKT_FLUSHREAD;
-               wake_up_interruptible(&tty->link->read_wait);
-       }
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-}
-
-/**
- *     n_tty_chars_in_buffer   -       report available bytes
- *     @tty: tty device
- *
- *     Report the number of characters buffered to be delivered to user
- *     at this instant in time.
- *
- *     Locking: read_lock
- */
-
-static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
-{
-       unsigned long flags;
-       ssize_t n = 0;
-
-       spin_lock_irqsave(&tty->read_lock, flags);
-       if (!tty->icanon) {
-               n = tty->read_cnt;
-       } else if (tty->canon_data) {
-               n = (tty->canon_head > tty->read_tail) ?
-                       tty->canon_head - tty->read_tail :
-                       tty->canon_head + (N_TTY_BUF_SIZE - tty->read_tail);
-       }
-       spin_unlock_irqrestore(&tty->read_lock, flags);
-       return n;
-}
-
-/**
- *     is_utf8_continuation    -       utf8 multibyte check
- *     @c: byte to check
- *
- *     Returns true if the utf8 character 'c' is a multibyte continuation
- *     character. We use this to correctly compute the on screen size
- *     of the character when printing
- */
-
-static inline int is_utf8_continuation(unsigned char c)
-{
-       return (c & 0xc0) == 0x80;
-}
-
-/**
- *     is_continuation         -       multibyte check
- *     @c: byte to check
- *
- *     Returns true if the utf8 character 'c' is a multibyte continuation
- *     character and the terminal is in unicode mode.
- */
-
-static inline int is_continuation(unsigned char c, struct tty_struct *tty)
-{
-       return I_IUTF8(tty) && is_utf8_continuation(c);
-}
-
-/**
- *     do_output_char                  -       output one character
- *     @c: character (or partial unicode symbol)
- *     @tty: terminal device
- *     @space: space available in tty driver write buffer
- *
- *     This is a helper function that handles one output character
- *     (including special characters like TAB, CR, LF, etc.),
- *     doing OPOST processing and putting the results in the
- *     tty driver's write buffer.
- *
- *     Note that Linux currently ignores TABDLY, CRDLY, VTDLY, FFDLY
- *     and NLDLY.  They simply aren't relevant in the world today.
- *     If you ever need them, add them here.
- *
- *     Returns the number of bytes of buffer space used or -1 if
- *     no space left.
- *
- *     Locking: should be called under the output_lock to protect
- *              the column state and space left in the buffer
- */
-
-static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
-{
-       int     spaces;
-
-       if (!space)
-               return -1;
-
-       switch (c) {
-       case '\n':
-               if (O_ONLRET(tty))
-                       tty->column = 0;
-               if (O_ONLCR(tty)) {
-                       if (space < 2)
-                               return -1;
-                       tty->canon_column = tty->column = 0;
-                       tty->ops->write(tty, "\r\n", 2);
-                       return 2;
-               }
-               tty->canon_column = tty->column;
-               break;
-       case '\r':
-               if (O_ONOCR(tty) && tty->column == 0)
-                       return 0;
-               if (O_OCRNL(tty)) {
-                       c = '\n';
-                       if (O_ONLRET(tty))
-                               tty->canon_column = tty->column = 0;
-                       break;
-               }
-               tty->canon_column = tty->column = 0;
-               break;
-       case '\t':
-               spaces = 8 - (tty->column & 7);
-               if (O_TABDLY(tty) == XTABS) {
-                       if (space < spaces)
-                               return -1;
-                       tty->column += spaces;
-                       tty->ops->write(tty, "        ", spaces);
-                       return spaces;
-               }
-               tty->column += spaces;
-               break;
-       case '\b':
-               if (tty->column > 0)
-                       tty->column--;
-               break;
-       default:
-               if (!iscntrl(c)) {
-                       if (O_OLCUC(tty))
-                               c = toupper(c);
-                       if (!is_continuation(c, tty))
-                               tty->column++;
-               }
-               break;
-       }
-
-       tty_put_char(tty, c);
-       return 1;
-}
-
-/**
- *     process_output                  -       output post processor
- *     @c: character (or partial unicode symbol)
- *     @tty: terminal device
- *
- *     Output one character with OPOST processing.
- *     Returns -1 when the output device is full and the character
- *     must be retried.
- *
- *     Locking: output_lock to protect column state and space left
- *              (also, this is called from n_tty_write under the
- *               tty layer write lock)
- */
-
-static int process_output(unsigned char c, struct tty_struct *tty)
-{
-       int     space, retval;
-
-       mutex_lock(&tty->output_lock);
-
-       space = tty_write_room(tty);
-       retval = do_output_char(c, tty, space);
-
-       mutex_unlock(&tty->output_lock);
-       if (retval < 0)
-               return -1;
-       else
-               return 0;
-}
-
-/**
- *     process_output_block            -       block post processor
- *     @tty: terminal device
- *     @buf: character buffer
- *     @nr: number of bytes to output
- *
- *     Output a block of characters with OPOST processing.
- *     Returns the number of characters output.
- *
- *     This path is used to speed up block console writes, among other
- *     things when processing blocks of output data. It handles only
- *     the simple cases normally found and helps to generate blocks of
- *     symbols for the console driver and thus improve performance.
- *
- *     Locking: output_lock to protect column state and space left
- *              (also, this is called from n_tty_write under the
- *               tty layer write lock)
- */
-
-static ssize_t process_output_block(struct tty_struct *tty,
-                                   const unsigned char *buf, unsigned int nr)
-{
-       int     space;
-       int     i;
-       const unsigned char *cp;
-
-       mutex_lock(&tty->output_lock);
-
-       space = tty_write_room(tty);
-       if (!space) {
-               mutex_unlock(&tty->output_lock);
-               return 0;
-       }
-       if (nr > space)
-               nr = space;
-
-       for (i = 0, cp = buf; i < nr; i++, cp++) {
-               unsigned char c = *cp;
-
-               switch (c) {
-               case '\n':
-                       if (O_ONLRET(tty))
-                               tty->column = 0;
-                       if (O_ONLCR(tty))
-                               goto break_out;
-                       tty->canon_column = tty->column;
-                       break;
-               case '\r':
-                       if (O_ONOCR(tty) && tty->column == 0)
-                               goto break_out;
-                       if (O_OCRNL(tty))
-                               goto break_out;
-                       tty->canon_column = tty->column = 0;
-                       break;
-               case '\t':
-                       goto break_out;
-               case '\b':
-                       if (tty->column > 0)
-                               tty->column--;
-                       break;
-               default:
-                       if (!iscntrl(c)) {
-                               if (O_OLCUC(tty))
-                                       goto break_out;
-                               if (!is_continuation(c, tty))
-                                       tty->column++;
-                       }
-                       break;
-               }
-       }
-break_out:
-       i = tty->ops->write(tty, buf, i);
-
-       mutex_unlock(&tty->output_lock);
-       return i;
-}
-
-/**
- *     process_echoes  -       write pending echo characters
- *     @tty: terminal device
- *
- *     Write previously buffered echo (and other ldisc-generated)
- *     characters to the tty.
- *
- *     Characters generated by the ldisc (including echoes) need to
- *     be buffered because the driver's write buffer can fill during
- *     heavy program output.  Echoing straight to the driver will
- *     often fail under these conditions, causing lost characters and
- *     resulting mismatches of ldisc state information.
- *
- *     Since the ldisc state must represent the characters actually sent
- *     to the driver at the time of the write, operations like certain
- *     changes in column state are also saved in the buffer and executed
- *     here.
- *
- *     A circular fifo buffer is used so that the most recent characters
- *     are prioritized.  Also, when control characters are echoed with a
- *     prefixed "^", the pair is treated atomically and thus not separated.
- *
- *     Locking: output_lock to protect column state and space left,
- *              echo_lock to protect the echo buffer
- */
-
-static void process_echoes(struct tty_struct *tty)
-{
-       int     space, nr;
-       unsigned char c;
-       unsigned char *cp, *buf_end;
-
-       if (!tty->echo_cnt)
-               return;
-
-       mutex_lock(&tty->output_lock);
-       mutex_lock(&tty->echo_lock);
-
-       space = tty_write_room(tty);
-
-       buf_end = tty->echo_buf + N_TTY_BUF_SIZE;
-       cp = tty->echo_buf + tty->echo_pos;
-       nr = tty->echo_cnt;
-       while (nr > 0) {
-               c = *cp;
-               if (c == ECHO_OP_START) {
-                       unsigned char op;
-                       unsigned char *opp;
-                       int no_space_left = 0;
-
-                       /*
-                        * If the buffer byte is the start of a multi-byte
-                        * operation, get the next byte, which is either the
-                        * op code or a control character value.
-                        */
-                       opp = cp + 1;
-                       if (opp == buf_end)
-                               opp -= N_TTY_BUF_SIZE;
-                       op = *opp;
-
-                       switch (op) {
-                               unsigned int num_chars, num_bs;
-
-                       case ECHO_OP_ERASE_TAB:
-                               if (++opp == buf_end)
-                                       opp -= N_TTY_BUF_SIZE;
-                               num_chars = *opp;
-
-                               /*
-                                * Determine how many columns to go back
-                                * in order to erase the tab.
-                                * This depends on the number of columns
-                                * used by other characters within the tab
-                                * area.  If this (modulo 8) count is from
-                                * the start of input rather than from a
-                                * previous tab, we offset by canon column.
-                                * Otherwise, tab spacing is normal.
-                                */
-                               if (!(num_chars & 0x80))
-                                       num_chars += tty->canon_column;
-                               num_bs = 8 - (num_chars & 7);
-
-                               if (num_bs > space) {
-                                       no_space_left = 1;
-                                       break;
-                               }
-                               space -= num_bs;
-                               while (num_bs--) {
-                                       tty_put_char(tty, '\b');
-                                       if (tty->column > 0)
-                                               tty->column--;
-                               }
-                               cp += 3;
-                               nr -= 3;
-                               break;
-
-                       case ECHO_OP_SET_CANON_COL:
-                               tty->canon_column = tty->column;
-                               cp += 2;
-                               nr -= 2;
-                               break;
-
-                       case ECHO_OP_MOVE_BACK_COL:
-                               if (tty->column > 0)
-                                       tty->column--;
-                               cp += 2;
-                               nr -= 2;
-                               break;
-
-                       case ECHO_OP_START:
-                               /* This is an escaped echo op start code */
-                               if (!space) {
-                                       no_space_left = 1;
-                                       break;
-                               }
-                               tty_put_char(tty, ECHO_OP_START);
-                               tty->column++;
-                               space--;
-                               cp += 2;
-                               nr -= 2;
-                               break;
-
-                       default:
-                               /*
-                                * If the op is not a special byte code,
-                                * it is a ctrl char tagged to be echoed
-                                * as "^X" (where X is the letter
-                                * representing the control char).
-                                * Note that we must ensure there is
-                                * enough space for the whole ctrl pair.
-                                *
-                                */
-                               if (space < 2) {
-                                       no_space_left = 1;
-                                       break;
-                               }
-                               tty_put_char(tty, '^');
-                               tty_put_char(tty, op ^ 0100);
-                               tty->column += 2;
-                               space -= 2;
-                               cp += 2;
-                               nr -= 2;
-                       }
-
-                       if (no_space_left)
-                               break;
-               } else {
-                       if (O_OPOST(tty) &&
-                           !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
-                               int retval = do_output_char(c, tty, space);
-                               if (retval < 0)
-                                       break;
-                               space -= retval;
-                       } else {
-                               if (!space)
-                                       break;
-                               tty_put_char(tty, c);
-                               space -= 1;
-                       }
-                       cp += 1;
-                       nr -= 1;
-               }
-
-               /* When end of circular buffer reached, wrap around */
-               if (cp >= buf_end)
-                       cp -= N_TTY_BUF_SIZE;
-       }
-
-       if (nr == 0) {
-               tty->echo_pos = 0;
-               tty->echo_cnt = 0;
-               tty->echo_overrun = 0;
-       } else {
-               int num_processed = tty->echo_cnt - nr;
-               tty->echo_pos += num_processed;
-               tty->echo_pos &= N_TTY_BUF_SIZE - 1;
-               tty->echo_cnt = nr;
-               if (num_processed > 0)
-                       tty->echo_overrun = 0;
-       }
-
-       mutex_unlock(&tty->echo_lock);
-       mutex_unlock(&tty->output_lock);
-
-       if (tty->ops->flush_chars)
-               tty->ops->flush_chars(tty);
-}
-
-/**
- *     add_echo_byte   -       add a byte to the echo buffer
- *     @c: unicode byte to echo
- *     @tty: terminal device
- *
- *     Add a character or operation byte to the echo buffer.
- *
- *     Should be called under the echo lock to protect the echo buffer.
- */
-
-static void add_echo_byte(unsigned char c, struct tty_struct *tty)
-{
-       int     new_byte_pos;
-
-       if (tty->echo_cnt == N_TTY_BUF_SIZE) {
-               /* Circular buffer is already at capacity */
-               new_byte_pos = tty->echo_pos;
-
-               /*
-                * Since the buffer start position needs to be advanced,
-                * be sure to step by a whole operation byte group.
-                */
-               if (tty->echo_buf[tty->echo_pos] == ECHO_OP_START) {
-                       if (tty->echo_buf[(tty->echo_pos + 1) &
-                                         (N_TTY_BUF_SIZE - 1)] ==
-                                               ECHO_OP_ERASE_TAB) {
-                               tty->echo_pos += 3;
-                               tty->echo_cnt -= 2;
-                       } else {
-                               tty->echo_pos += 2;
-                               tty->echo_cnt -= 1;
-                       }
-               } else {
-                       tty->echo_pos++;
-               }
-               tty->echo_pos &= N_TTY_BUF_SIZE - 1;
-
-               tty->echo_overrun = 1;
-       } else {
-               new_byte_pos = tty->echo_pos + tty->echo_cnt;
-               new_byte_pos &= N_TTY_BUF_SIZE - 1;
-               tty->echo_cnt++;
-       }
-
-       tty->echo_buf[new_byte_pos] = c;
-}
-
-/**
- *     echo_move_back_col      -       add operation to move back a column
- *     @tty: terminal device
- *
- *     Add an operation to the echo buffer to move back one column.
- *
- *     Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_move_back_col(struct tty_struct *tty)
-{
-       mutex_lock(&tty->echo_lock);
-
-       add_echo_byte(ECHO_OP_START, tty);
-       add_echo_byte(ECHO_OP_MOVE_BACK_COL, tty);
-
-       mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *     echo_set_canon_col      -       add operation to set the canon column
- *     @tty: terminal device
- *
- *     Add an operation to the echo buffer to set the canon column
- *     to the current column.
- *
- *     Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_set_canon_col(struct tty_struct *tty)
-{
-       mutex_lock(&tty->echo_lock);
-
-       add_echo_byte(ECHO_OP_START, tty);
-       add_echo_byte(ECHO_OP_SET_CANON_COL, tty);
-
-       mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *     echo_erase_tab  -       add operation to erase a tab
- *     @num_chars: number of character columns already used
- *     @after_tab: true if num_chars starts after a previous tab
- *     @tty: terminal device
- *
- *     Add an operation to the echo buffer to erase a tab.
- *
- *     Called by the eraser function, which knows how many character
- *     columns have been used since either a previous tab or the start
- *     of input.  This information will be used later, along with
- *     canon column (if applicable), to go back the correct number
- *     of columns.
- *
- *     Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_erase_tab(unsigned int num_chars, int after_tab,
-                          struct tty_struct *tty)
-{
-       mutex_lock(&tty->echo_lock);
-
-       add_echo_byte(ECHO_OP_START, tty);
-       add_echo_byte(ECHO_OP_ERASE_TAB, tty);
-
-       /* We only need to know this modulo 8 (tab spacing) */
-       num_chars &= 7;
-
-       /* Set the high bit as a flag if num_chars is after a previous tab */
-       if (after_tab)
-               num_chars |= 0x80;
-
-       add_echo_byte(num_chars, tty);
-
-       mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *     echo_char_raw   -       echo a character raw
- *     @c: unicode byte to echo
- *     @tty: terminal device
- *
- *     Echo user input back onto the screen. This must be called only when
- *     L_ECHO(tty) is true. Called from the driver receive_buf path.
- *
- *     This variant does not treat control characters specially.
- *
- *     Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_char_raw(unsigned char c, struct tty_struct *tty)
-{
-       mutex_lock(&tty->echo_lock);
-
-       if (c == ECHO_OP_START) {
-               add_echo_byte(ECHO_OP_START, tty);
-               add_echo_byte(ECHO_OP_START, tty);
-       } else {
-               add_echo_byte(c, tty);
-       }
-
-       mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *     echo_char       -       echo a character
- *     @c: unicode byte to echo
- *     @tty: terminal device
- *
- *     Echo user input back onto the screen. This must be called only when
- *     L_ECHO(tty) is true. Called from the driver receive_buf path.
- *
- *     This variant tags control characters to be echoed as "^X"
- *     (where X is the letter representing the control char).
- *
- *     Locking: echo_lock to protect the echo buffer
- */
-
-static void echo_char(unsigned char c, struct tty_struct *tty)
-{
-       mutex_lock(&tty->echo_lock);
-
-       if (c == ECHO_OP_START) {
-               add_echo_byte(ECHO_OP_START, tty);
-               add_echo_byte(ECHO_OP_START, tty);
-       } else {
-               if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t')
-                       add_echo_byte(ECHO_OP_START, tty);
-               add_echo_byte(c, tty);
-       }
-
-       mutex_unlock(&tty->echo_lock);
-}
-
-/**
- *     finish_erasing          -       complete erase
- *     @tty: tty doing the erase
- */
-
-static inline void finish_erasing(struct tty_struct *tty)
-{
-       if (tty->erasing) {
-               echo_char_raw('/', tty);
-               tty->erasing = 0;
-       }
-}
-
-/**
- *     eraser          -       handle erase function
- *     @c: character input
- *     @tty: terminal device
- *
- *     Perform erase and necessary output when an erase character is
- *     present in the stream from the driver layer. Handles the complexities
- *     of UTF-8 multibyte symbols.
- *
- *     Locking: read_lock for tty buffers
- */
-
-static void eraser(unsigned char c, struct tty_struct *tty)
-{
-       enum { ERASE, WERASE, KILL } kill_type;
-       int head, seen_alnums, cnt;
-       unsigned long flags;
-
-       /* FIXME: locking needed ? */
-       if (tty->read_head == tty->canon_head) {
-               /* process_output('\a', tty); */ /* what do you think? */
-               return;
-       }
-       if (c == ERASE_CHAR(tty))
-               kill_type = ERASE;
-       else if (c == WERASE_CHAR(tty))
-               kill_type = WERASE;
-       else {
-               if (!L_ECHO(tty)) {
-                       spin_lock_irqsave(&tty->read_lock, flags);
-                       tty->read_cnt -= ((tty->read_head - tty->canon_head) &
-                                         (N_TTY_BUF_SIZE - 1));
-                       tty->read_head = tty->canon_head;
-                       spin_unlock_irqrestore(&tty->read_lock, flags);
-                       return;
-               }
-               if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
-                       spin_lock_irqsave(&tty->read_lock, flags);
-                       tty->read_cnt -= ((tty->read_head - tty->canon_head) &
-                                         (N_TTY_BUF_SIZE - 1));
-                       tty->read_head = tty->canon_head;
-                       spin_unlock_irqrestore(&tty->read_lock, flags);
-                       finish_erasing(tty);
-                       echo_char(KILL_CHAR(tty), tty);
-                       /* Add a newline if ECHOK is on and ECHOKE is off. */
-                       if (L_ECHOK(tty))
-                               echo_char_raw('\n', tty);
-                       return;
-               }
-               kill_type = KILL;
-       }
-
-       seen_alnums = 0;
-       /* FIXME: Locking ?? */
-       while (tty->read_head != tty->canon_head) {
-               head = tty->read_head;
-
-               /* erase a single possibly multibyte character */
-               do {
-                       head = (head - 1) & (N_TTY_BUF_SIZE-1);
-                       c = tty->read_buf[head];
-               } while (is_continuation(c, tty) && head != tty->canon_head);
-
-               /* do not partially erase */
-               if (is_continuation(c, tty))
-                       break;
-
-               if (kill_type == WERASE) {
-                       /* Equivalent to BSD's ALTWERASE. */
-                       if (isalnum(c) || c == '_')
-                               seen_alnums++;
-                       else if (seen_alnums)
-                               break;
-               }
-               cnt = (tty->read_head - head) & (N_TTY_BUF_SIZE-1);
-               spin_lock_irqsave(&tty->read_lock, flags);
-               tty->read_head = head;
-               tty->read_cnt -= cnt;
-               spin_unlock_irqrestore(&tty->read_lock, flags);
-               if (L_ECHO(tty)) {
-                       if (L_ECHOPRT(tty)) {
-                               if (!tty->erasing) {
-                                       echo_char_raw('\\', tty);
-                                       tty->erasing = 1;
-                               }
-                               /* if cnt > 1, output a multi-byte character */
-                               echo_char(c, tty);
-                               while (--cnt > 0) {
-                                       head = (head+1) & (N_TTY_BUF_SIZE-1);
-                                       echo_char_raw(tty->read_buf[head], tty);
-                                       echo_move_back_col(tty);
-                               }
-                       } else if (kill_type == ERASE && !L_ECHOE(tty)) {
-                               echo_char(ERASE_CHAR(tty), tty);
-                       } else if (c == '\t') {
-                               unsigned int num_chars = 0;
-                               int after_tab = 0;
-                               unsigned long tail = tty->read_head;
-
-                               /*
-                                * Count the columns used for characters
-                                * since the start of input or after a
-                                * previous tab.
-                                * This info is used to go back the correct
-                                * number of columns.
-                                */
-                               while (tail != tty->canon_head) {
-                                       tail = (tail-1) & (N_TTY_BUF_SIZE-1);
-                                       c = tty->read_buf[tail];
-                                       if (c == '\t') {
-                                               after_tab = 1;
-                                               break;
-                                       } else if (iscntrl(c)) {
-                                               if (L_ECHOCTL(tty))
-                                                       num_chars += 2;
-                                       } else if (!is_continuation(c, tty)) {
-                                               num_chars++;
-                                       }
-                               }
-                               echo_erase_tab(num_chars, after_tab, tty);
-                       } else {
-                               if (iscntrl(c) && L_ECHOCTL(tty)) {
-                                       echo_char_raw('\b', tty);
-                                       echo_char_raw(' ', tty);
-                                       echo_char_raw('\b', tty);
-                               }
-                               if (!iscntrl(c) || L_ECHOCTL(tty)) {
-                                       echo_char_raw('\b', tty);
-                                       echo_char_raw(' ', tty);
-                                       echo_char_raw('\b', tty);
-                               }
-                       }
-               }
-               if (kill_type == ERASE)
-                       break;
-       }
-       if (tty->read_head == tty->canon_head && L_ECHO(tty))
-               finish_erasing(tty);
-}
-
-/**
- *     isig            -       handle the ISIG optio
- *     @sig: signal
- *     @tty: terminal
- *     @flush: force flush
- *
- *     Called when a signal is being sent due to terminal input. This
- *     may caus terminal flushing to take place according to the termios
- *     settings and character used. Called from the driver receive_buf
- *     path so serialized.
- *
- *     Locking: ctrl_lock, read_lock (both via flush buffer)
- */
-
-static inline void isig(int sig, struct tty_struct *tty, int flush)
-{
-       if (tty->pgrp)
-               kill_pgrp(tty->pgrp, sig, 1);
-       if (flush || !L_NOFLSH(tty)) {
-               n_tty_flush_buffer(tty);
-               tty_driver_flush_buffer(tty);
-       }
-}
-
-/**
- *     n_tty_receive_break     -       handle break
- *     @tty: terminal
- *
- *     An RS232 break event has been hit in the incoming bitstream. This
- *     can cause a variety of events depending upon the termios settings.
- *
- *     Called from the receive_buf path so single threaded.
- */
-
-static inline void n_tty_receive_break(struct tty_struct *tty)
-{
-       if (I_IGNBRK(tty))
-               return;
-       if (I_BRKINT(tty)) {
-               isig(SIGINT, tty, 1);
-               return;
-       }
-       if (I_PARMRK(tty)) {
-               put_tty_queue('\377', tty);
-               put_tty_queue('\0', tty);
-       }
-       put_tty_queue('\0', tty);
-       wake_up_interruptible(&tty->read_wait);
-}
-
-/**
- *     n_tty_receive_overrun   -       handle overrun reporting
- *     @tty: terminal
- *
- *     Data arrived faster than we could process it. While the tty
- *     driver has flagged this the bits that were missed are gone
- *     forever.
- *
- *     Called from the receive_buf path so single threaded. Does not
- *     need locking as num_overrun and overrun_time are function
- *     private.
- */
-
-static inline void n_tty_receive_overrun(struct tty_struct *tty)
-{
-       char buf[64];
-
-       tty->num_overrun++;
-       if (time_before(tty->overrun_time, jiffies - HZ) ||
-                       time_after(tty->overrun_time, jiffies)) {
-               printk(KERN_WARNING "%s: %d input overrun(s)\n",
-                       tty_name(tty, buf),
-                       tty->num_overrun);
-               tty->overrun_time = jiffies;
-               tty->num_overrun = 0;
-       }
-}
-
-/**
- *     n_tty_receive_parity_error      -       error notifier
- *     @tty: terminal device
- *     @c: character
- *
- *     Process a parity error and queue the right data to indicate
- *     the error case if necessary. Locking as per n_tty_receive_buf.
- */
-static inline void n_tty_receive_parity_error(struct tty_struct *tty,
-                                             unsigned char c)
-{
-       if (I_IGNPAR(tty))
-               return;
-       if (I_PARMRK(tty)) {
-               put_tty_queue('\377', tty);
-               put_tty_queue('\0', tty);
-               put_tty_queue(c, tty);
-       } else  if (I_INPCK(tty))
-               put_tty_queue('\0', tty);
-       else
-               put_tty_queue(c, tty);
-       wake_up_interruptible(&tty->read_wait);
-}
-
-/**
- *     n_tty_receive_char      -       perform processing
- *     @tty: terminal device
- *     @c: character
- *
- *     Process an individual character of input received from the driver.
- *     This is serialized with respect to itself by the rules for the
- *     driver above.
- */
-
-static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
-{
-       unsigned long flags;
-       int parmrk;
-
-       if (tty->raw) {
-               put_tty_queue(c, tty);
-               return;
-       }
-
-       if (I_ISTRIP(tty))
-               c &= 0x7f;
-       if (I_IUCLC(tty) && L_IEXTEN(tty))
-               c = tolower(c);
-
-       if (L_EXTPROC(tty)) {
-               put_tty_queue(c, tty);
-               return;
-       }
-
-       if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
-           I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty) &&
-           c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty)) {
-               start_tty(tty);
-               process_echoes(tty);
-       }
-
-       if (tty->closing) {
-               if (I_IXON(tty)) {
-                       if (c == START_CHAR(tty)) {
-                               start_tty(tty);
-                               process_echoes(tty);
-                       } else if (c == STOP_CHAR(tty))
-                               stop_tty(tty);
-               }
-               return;
-       }
-
-       /*
-        * If the previous character was LNEXT, or we know that this
-        * character is not one of the characters that we'll have to
-        * handle specially, do shortcut processing to speed things
-        * up.
-        */
-       if (!test_bit(c, tty->process_char_map) || tty->lnext) {
-               tty->lnext = 0;
-               parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
-               if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
-                       /* beep if no space */
-                       if (L_ECHO(tty))
-                               process_output('\a', tty);
-                       return;
-               }
-               if (L_ECHO(tty)) {
-                       finish_erasing(tty);
-                       /* Record the column of first canon char. */
-                       if (tty->canon_head == tty->read_head)
-                               echo_set_canon_col(tty);
-                       echo_char(c, tty);
-                       process_echoes(tty);
-               }
-               if (parmrk)
-                       put_tty_queue(c, tty);
-               put_tty_queue(c, tty);
-               return;
-       }
-
-       if (I_IXON(tty)) {
-               if (c == START_CHAR(tty)) {
-                       start_tty(tty);
-                       process_echoes(tty);
-                       return;
-               }
-               if (c == STOP_CHAR(tty)) {
-                       stop_tty(tty);
-                       return;
-               }
-       }
-
-       if (L_ISIG(tty)) {
-               int signal;
-               signal = SIGINT;
-               if (c == INTR_CHAR(tty))
-                       goto send_signal;
-               signal = SIGQUIT;
-               if (c == QUIT_CHAR(tty))
-                       goto send_signal;
-               signal = SIGTSTP;
-               if (c == SUSP_CHAR(tty)) {
-send_signal:
-                       /*
-                        * Note that we do not use isig() here because we want
-                        * the order to be:
-                        * 1) flush, 2) echo, 3) signal
-                        */
-                       if (!L_NOFLSH(tty)) {
-                               n_tty_flush_buffer(tty);
-                               tty_driver_flush_buffer(tty);
-                       }
-                       if (I_IXON(tty))
-                               start_tty(tty);
-                       if (L_ECHO(tty)) {
-                               echo_char(c, tty);
-                               process_echoes(tty);
-                       }
-                       if (tty->pgrp)
-                               kill_pgrp(tty->pgrp, signal, 1);
-                       return;
-               }
-       }
-
-       if (c == '\r') {
-               if (I_IGNCR(tty))
-                       return;
-               if (I_ICRNL(tty))
-                       c = '\n';
-       } else if (c == '\n' && I_INLCR(tty))
-               c = '\r';
-
-       if (tty->icanon) {
-               if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
-                   (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
-                       eraser(c, tty);
-                       process_echoes(tty);
-                       return;
-               }
-               if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
-                       tty->lnext = 1;
-                       if (L_ECHO(tty)) {
-                               finish_erasing(tty);
-                               if (L_ECHOCTL(tty)) {
-                                       echo_char_raw('^', tty);
-                                       echo_char_raw('\b', tty);
-                                       process_echoes(tty);
-                               }
-                       }
-                       return;
-               }
-               if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
-                   L_IEXTEN(tty)) {
-                       unsigned long tail = tty->canon_head;
-
-                       finish_erasing(tty);
-                       echo_char(c, tty);
-                       echo_char_raw('\n', tty);
-                       while (tail != tty->read_head) {
-                               echo_char(tty->read_buf[tail], tty);
-                               tail = (tail+1) & (N_TTY_BUF_SIZE-1);
-                       }
-                       process_echoes(tty);
-                       return;
-               }
-               if (c == '\n') {
-                       if (tty->read_cnt >= N_TTY_BUF_SIZE) {
-                               if (L_ECHO(tty))
-                                       process_output('\a', tty);
-                               return;
-                       }
-                       if (L_ECHO(tty) || L_ECHONL(tty)) {
-                               echo_char_raw('\n', tty);
-                               process_echoes(tty);
-                       }
-                       goto handle_newline;
-               }
-               if (c == EOF_CHAR(tty)) {
-                       if (tty->read_cnt >= N_TTY_BUF_SIZE)
-                               return;
-                       if (tty->canon_head != tty->read_head)
-                               set_bit(TTY_PUSH, &tty->flags);
-                       c = __DISABLED_CHAR;
-                       goto handle_newline;
-               }
-               if ((c == EOL_CHAR(tty)) ||
-                   (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
-                       parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
-                                ? 1 : 0;
-                       if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
-                               if (L_ECHO(tty))
-                                       process_output('\a', tty);
-                               return;
-                       }
-                       /*
-                        * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
-                        */
-                       if (L_ECHO(tty)) {
-                               /* Record the column of first canon char. */
-                               if (tty->canon_head == tty->read_head)
-                                       echo_set_canon_col(tty);
-                               echo_char(c, tty);
-                               process_echoes(tty);
-                       }
-                       /*
-                        * XXX does PARMRK doubling happen for
-                        * EOL_CHAR and EOL2_CHAR?
-                        */
-                       if (parmrk)
-                               put_tty_queue(c, tty);
-
-handle_newline:
-                       spin_lock_irqsave(&tty->read_lock, flags);
-                       set_bit(tty->read_head, tty->read_flags);
-                       put_tty_queue_nolock(c, tty);
-                       tty->canon_head = tty->read_head;
-                       tty->canon_data++;
-                       spin_unlock_irqrestore(&tty->read_lock, flags);
-                       kill_fasync(&tty->fasync, SIGIO, POLL_IN);
-                       if (waitqueue_active(&tty->read_wait))
-                               wake_up_interruptible(&tty->read_wait);
-                       return;
-               }
-       }
-
-       parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
-       if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
-               /* beep if no space */
-               if (L_ECHO(tty))
-                       process_output('\a', tty);
-               return;
-       }
-       if (L_ECHO(tty)) {
-               finish_erasing(tty);
-               if (c == '\n')
-                       echo_char_raw('\n', tty);
-               else {
-                       /* Record the column of first canon char. */
-                       if (tty->canon_head == tty->read_head)
-                               echo_set_canon_col(tty);
-                       echo_char(c, tty);
-               }
-               process_echoes(tty);
-       }
-
-       if (parmrk)
-               put_tty_queue(c, tty);
-
-       put_tty_queue(c, tty);
-}
-
-
-/**
- *     n_tty_write_wakeup      -       asynchronous I/O notifier
- *     @tty: tty device
- *
- *     Required for the ptys, serial driver etc. since processes
- *     that attach themselves to the master and rely on ASYNC
- *     IO must be woken up
- */
-
-static void n_tty_write_wakeup(struct tty_struct *tty)
-{
-       if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags))
-               kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
-}
-
-/**
- *     n_tty_receive_buf       -       data receive
- *     @tty: terminal device
- *     @cp: buffer
- *     @fp: flag buffer
- *     @count: characters
- *
- *     Called by the terminal driver when a block of characters has
- *     been received. This function must be called from soft contexts
- *     not from interrupt context. The driver is responsible for making
- *     calls one at a time and in order (or using flush_to_ldisc)
- */
-
-static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-                             char *fp, int count)
-{
-       const unsigned char *p;
-       char *f, flags = TTY_NORMAL;
-       int     i;
-       char    buf[64];
-       unsigned long cpuflags;
-
-       if (!tty->read_buf)
-               return;
-
-       if (tty->real_raw) {
-               spin_lock_irqsave(&tty->read_lock, cpuflags);
-               i = min(N_TTY_BUF_SIZE - tty->read_cnt,
-                       N_TTY_BUF_SIZE - tty->read_head);
-               i = min(count, i);
-               memcpy(tty->read_buf + tty->read_head, cp, i);
-               tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
-               tty->read_cnt += i;
-               cp += i;
-               count -= i;
-
-               i = min(N_TTY_BUF_SIZE - tty->read_cnt,
-                       N_TTY_BUF_SIZE - tty->read_head);
-               i = min(count, i);
-               memcpy(tty->read_buf + tty->read_head, cp, i);
-               tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
-               tty->read_cnt += i;
-               spin_unlock_irqrestore(&tty->read_lock, cpuflags);
-       } else {
-               for (i = count, p = cp, f = fp; i; i--, p++) {
-                       if (f)
-                               flags = *f++;
-                       switch (flags) {
-                       case TTY_NORMAL:
-                               n_tty_receive_char(tty, *p);
-                               break;
-                       case TTY_BREAK:
-                               n_tty_receive_break(tty);
-                               break;
-                       case TTY_PARITY:
-                       case TTY_FRAME:
-                               n_tty_receive_parity_error(tty, *p);
-                               break;
-                       case TTY_OVERRUN:
-                               n_tty_receive_overrun(tty);
-                               break;
-                       default:
-                               printk(KERN_ERR "%s: unknown flag %d\n",
-                                      tty_name(tty, buf), flags);
-                               break;
-                       }
-               }
-               if (tty->ops->flush_chars)
-                       tty->ops->flush_chars(tty);
-       }
-
-       n_tty_set_room(tty);
-
-       if ((!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) ||
-               L_EXTPROC(tty)) {
-               kill_fasync(&tty->fasync, SIGIO, POLL_IN);
-               if (waitqueue_active(&tty->read_wait))
-                       wake_up_interruptible(&tty->read_wait);
-       }
-
-       /*
-        * Check the remaining room for the input canonicalization
-        * mode.  We don't want to throttle the driver if we're in
-        * canonical mode and don't have a newline yet!
-        */
-       if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
-               tty_throttle(tty);
-}
-
-int is_ignored(int sig)
-{
-       return (sigismember(&current->blocked, sig) ||
-               current->sighand->action[sig-1].sa.sa_handler == SIG_IGN);
-}
-
-/**
- *     n_tty_set_termios       -       termios data changed
- *     @tty: terminal
- *     @old: previous data
- *
- *     Called by the tty layer when the user changes termios flags so
- *     that the line discipline can plan ahead. This function cannot sleep
- *     and is protected from re-entry by the tty layer. The user is
- *     guaranteed that this function will not be re-entered or in progress
- *     when the ldisc is closed.
- *
- *     Locking: Caller holds tty->termios_mutex
- */
-
-static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
-{
-       int canon_change = 1;
-       BUG_ON(!tty);
-
-       if (old)
-               canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON;
-       if (canon_change) {
-               memset(&tty->read_flags, 0, sizeof tty->read_flags);
-               tty->canon_head = tty->read_tail;
-               tty->canon_data = 0;
-               tty->erasing = 0;
-       }
-
-       if (canon_change && !L_ICANON(tty) && tty->read_cnt)
-               wake_up_interruptible(&tty->read_wait);
-
-       tty->icanon = (L_ICANON(tty) != 0);
-       if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
-               tty->raw = 1;
-               tty->real_raw = 1;
-               n_tty_set_room(tty);
-               return;
-       }
-       if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
-           I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
-           I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
-           I_PARMRK(tty)) {
-               memset(tty->process_char_map, 0, 256/8);
-
-               if (I_IGNCR(tty) || I_ICRNL(tty))
-                       set_bit('\r', tty->process_char_map);
-               if (I_INLCR(tty))
-                       set_bit('\n', tty->process_char_map);
-
-               if (L_ICANON(tty)) {
-                       set_bit(ERASE_CHAR(tty), tty->process_char_map);
-                       set_bit(KILL_CHAR(tty), tty->process_char_map);
-                       set_bit(EOF_CHAR(tty), tty->process_char_map);
-                       set_bit('\n', tty->process_char_map);
-                       set_bit(EOL_CHAR(tty), tty->process_char_map);
-                       if (L_IEXTEN(tty)) {
-                               set_bit(WERASE_CHAR(tty),
-                                       tty->process_char_map);
-                               set_bit(LNEXT_CHAR(tty),
-                                       tty->process_char_map);
-                               set_bit(EOL2_CHAR(tty),
-                                       tty->process_char_map);
-                               if (L_ECHO(tty))
-                                       set_bit(REPRINT_CHAR(tty),
-                                               tty->process_char_map);
-                       }
-               }
-               if (I_IXON(tty)) {
-                       set_bit(START_CHAR(tty), tty->process_char_map);
-                       set_bit(STOP_CHAR(tty), tty->process_char_map);
-               }
-               if (L_ISIG(tty)) {
-                       set_bit(INTR_CHAR(tty), tty->process_char_map);
-                       set_bit(QUIT_CHAR(tty), tty->process_char_map);
-                       set_bit(SUSP_CHAR(tty), tty->process_char_map);
-               }
-               clear_bit(__DISABLED_CHAR, tty->process_char_map);
-               tty->raw = 0;
-               tty->real_raw = 0;
-       } else {
-               tty->raw = 1;
-               if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&
-                   (I_IGNPAR(tty) || !I_INPCK(tty)) &&
-                   (tty->driver->flags & TTY_DRIVER_REAL_RAW))
-                       tty->real_raw = 1;
-               else
-                       tty->real_raw = 0;
-       }
-       n_tty_set_room(tty);
-       /* The termios change make the tty ready for I/O */
-       wake_up_interruptible(&tty->write_wait);
-       wake_up_interruptible(&tty->read_wait);
-}
-
-/**
- *     n_tty_close             -       close the ldisc for this tty
- *     @tty: device
- *
- *     Called from the terminal layer when this line discipline is
- *     being shut down, either because of a close or becsuse of a
- *     discipline change. The function will not be called while other
- *     ldisc methods are in progress.
- */
-
-static void n_tty_close(struct tty_struct *tty)
-{
-       n_tty_flush_buffer(tty);
-       if (tty->read_buf) {
-               kfree(tty->read_buf);
-               tty->read_buf = NULL;
-       }
-       if (tty->echo_buf) {
-               kfree(tty->echo_buf);
-               tty->echo_buf = NULL;
-       }
-}
-
-/**
- *     n_tty_open              -       open an ldisc
- *     @tty: terminal to open
- *
- *     Called when this line discipline is being attached to the
- *     terminal device. Can sleep. Called serialized so that no
- *     other events will occur in parallel. No further open will occur
- *     until a close.
- */
-
-static int n_tty_open(struct tty_struct *tty)
-{
-       if (!tty)
-               return -EINVAL;
-
-       /* These are ugly. Currently a malloc failure here can panic */
-       if (!tty->read_buf) {
-               tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
-               if (!tty->read_buf)
-                       return -ENOMEM;
-       }
-       if (!tty->echo_buf) {
-               tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
-
-               if (!tty->echo_buf)
-                       return -ENOMEM;
-       }
-       reset_buffer_flags(tty);
-       tty->column = 0;
-       n_tty_set_termios(tty, NULL);
-       tty->minimum_to_wake = 1;
-       tty->closing = 0;
-       return 0;
-}
-
-static inline int input_available_p(struct tty_struct *tty, int amt)
-{
-       tty_flush_to_ldisc(tty);
-       if (tty->icanon && !L_EXTPROC(tty)) {
-               if (tty->canon_data)
-                       return 1;
-       } else if (tty->read_cnt >= (amt ? amt : 1))
-               return 1;
-
-       return 0;
-}
-
-/**
- *     copy_from_read_buf      -       copy read data directly
- *     @tty: terminal device
- *     @b: user data
- *     @nr: size of data
- *
- *     Helper function to speed up n_tty_read.  It is only called when
- *     ICANON is off; it copies characters straight from the tty queue to
- *     user space directly.  It can be profitably called twice; once to
- *     drain the space from the tail pointer to the (physical) end of the
- *     buffer, and once to drain the space from the (physical) beginning of
- *     the buffer to head pointer.
- *
- *     Called under the tty->atomic_read_lock sem
- *
- */
-
-static int copy_from_read_buf(struct tty_struct *tty,
-                                     unsigned char __user **b,
-                                     size_t *nr)
-
-{
-       int retval;
-       size_t n;
-       unsigned long flags;
-
-       retval = 0;
-       spin_lock_irqsave(&tty->read_lock, flags);
-       n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail);
-       n = min(*nr, n);
-       spin_unlock_irqrestore(&tty->read_lock, flags);
-       if (n) {
-               retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
-               n -= retval;
-               tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
-               spin_lock_irqsave(&tty->read_lock, flags);
-               tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
-               tty->read_cnt -= n;
-               /* Turn single EOF into zero-length read */
-               if (L_EXTPROC(tty) && tty->icanon && n == 1) {
-                       if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
-                               n--;
-               }
-               spin_unlock_irqrestore(&tty->read_lock, flags);
-               *b += n;
-               *nr -= n;
-       }
-       return retval;
-}
-
-extern ssize_t redirected_tty_write(struct file *, const char __user *,
-                                                       size_t, loff_t *);
-
-/**
- *     job_control             -       check job control
- *     @tty: tty
- *     @file: file handle
- *
- *     Perform job control management checks on this file/tty descriptor
- *     and if appropriate send any needed signals and return a negative
- *     error code if action should be taken.
- *
- *     FIXME:
- *     Locking: None - redirected write test is safe, testing
- *     current->signal should possibly lock current->sighand
- *     pgrp locking ?
- */
-
-static int job_control(struct tty_struct *tty, struct file *file)
-{
-       /* Job control check -- must be done at start and after
-          every sleep (POSIX.1 7.1.1.4). */
-       /* NOTE: not yet done after every sleep pending a thorough
-          check of the logic of this change. -- jlc */
-       /* don't stop on /dev/console */
-       if (file->f_op->write != redirected_tty_write &&
-           current->signal->tty == tty) {
-               if (!tty->pgrp)
-                       printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
-               else if (task_pgrp(current) != tty->pgrp) {
-                       if (is_ignored(SIGTTIN) ||
-                           is_current_pgrp_orphaned())
-                               return -EIO;
-                       kill_pgrp(task_pgrp(current), SIGTTIN, 1);
-                       set_thread_flag(TIF_SIGPENDING);
-                       return -ERESTARTSYS;
-               }
-       }
-       return 0;
-}
-
-
-/**
- *     n_tty_read              -       read function for tty
- *     @tty: tty device
- *     @file: file object
- *     @buf: userspace buffer pointer
- *     @nr: size of I/O
- *
- *     Perform reads for the line discipline. We are guaranteed that the
- *     line discipline will not be closed under us but we may get multiple
- *     parallel readers and must handle this ourselves. We may also get
- *     a hangup. Always called in user context, may sleep.
- *
- *     This code must be sure never to sleep through a hangup.
- */
-
-static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
-                        unsigned char __user *buf, size_t nr)
-{
-       unsigned char __user *b = buf;
-       DECLARE_WAITQUEUE(wait, current);
-       int c;
-       int minimum, time;
-       ssize_t retval = 0;
-       ssize_t size;
-       long timeout;
-       unsigned long flags;
-       int packet;
-
-do_it_again:
-
-       BUG_ON(!tty->read_buf);
-
-       c = job_control(tty, file);
-       if (c < 0)
-               return c;
-
-       minimum = time = 0;
-       timeout = MAX_SCHEDULE_TIMEOUT;
-       if (!tty->icanon) {
-               time = (HZ / 10) * TIME_CHAR(tty);
-               minimum = MIN_CHAR(tty);
-               if (minimum) {
-                       if (time)
-                               tty->minimum_to_wake = 1;
-                       else if (!waitqueue_active(&tty->read_wait) ||
-                                (tty->minimum_to_wake > minimum))
-                               tty->minimum_to_wake = minimum;
-               } else {
-                       timeout = 0;
-                       if (time) {
-                               timeout = time;
-                               time = 0;
-                       }
-                       tty->minimum_to_wake = minimum = 1;
-               }
-       }
-
-       /*
-        *      Internal serialization of reads.
-        */
-       if (file->f_flags & O_NONBLOCK) {
-               if (!mutex_trylock(&tty->atomic_read_lock))
-                       return -EAGAIN;
-       } else {
-               if (mutex_lock_interruptible(&tty->atomic_read_lock))
-                       return -ERESTARTSYS;
-       }
-       packet = tty->packet;
-
-       add_wait_queue(&tty->read_wait, &wait);
-       while (nr) {
-               /* First test for status change. */
-               if (packet && tty->link->ctrl_status) {
-                       unsigned char cs;
-                       if (b != buf)
-                               break;
-                       spin_lock_irqsave(&tty->link->ctrl_lock, flags);
-                       cs = tty->link->ctrl_status;
-                       tty->link->ctrl_status = 0;
-                       spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
-                       if (tty_put_user(tty, cs, b++)) {
-                               retval = -EFAULT;
-                               b--;
-                               break;
-                       }
-                       nr--;
-                       break;
-               }
-               /* This statement must be first before checking for input
-                  so that any interrupt will set the state back to
-                  TASK_RUNNING. */
-               set_current_state(TASK_INTERRUPTIBLE);
-
-               if (((minimum - (b - buf)) < tty->minimum_to_wake) &&
-                   ((minimum - (b - buf)) >= 1))
-                       tty->minimum_to_wake = (minimum - (b - buf));
-
-               if (!input_available_p(tty, 0)) {
-                       if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
-                               retval = -EIO;
-                               break;
-                       }
-                       if (tty_hung_up_p(file))
-                               break;
-                       if (!timeout)
-                               break;
-                       if (file->f_flags & O_NONBLOCK) {
-                               retval = -EAGAIN;
-                               break;
-                       }
-                       if (signal_pending(current)) {
-                               retval = -ERESTARTSYS;
-                               break;
-                       }
-                       /* FIXME: does n_tty_set_room need locking ? */
-                       n_tty_set_room(tty);
-                       timeout = schedule_timeout(timeout);
-                       continue;
-               }
-               __set_current_state(TASK_RUNNING);
-
-               /* Deal with packet mode. */
-               if (packet && b == buf) {
-                       if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
-                               retval = -EFAULT;
-                               b--;
-                               break;
-                       }
-                       nr--;
-               }
-
-               if (tty->icanon && !L_EXTPROC(tty)) {
-                       /* N.B. avoid overrun if nr == 0 */
-                       while (nr && tty->read_cnt) {
-                               int eol;
-
-                               eol = test_and_clear_bit(tty->read_tail,
-                                               tty->read_flags);
-                               c = tty->read_buf[tty->read_tail];
-                               spin_lock_irqsave(&tty->read_lock, flags);
-                               tty->read_tail = ((tty->read_tail+1) &
-                                                 (N_TTY_BUF_SIZE-1));
-                               tty->read_cnt--;
-                               if (eol) {
-                                       /* this test should be redundant:
-                                        * we shouldn't be reading data if
-                                        * canon_data is 0
-                                        */
-                                       if (--tty->canon_data < 0)
-                                               tty->canon_data = 0;
-                               }
-                               spin_unlock_irqrestore(&tty->read_lock, flags);
-
-                               if (!eol || (c != __DISABLED_CHAR)) {
-                                       if (tty_put_user(tty, c, b++)) {
-                                               retval = -EFAULT;
-                                               b--;
-                                               break;
-                                       }
-                                       nr--;
-                               }
-                               if (eol) {
-                                       tty_audit_push(tty);
-                                       break;
-                               }
-                       }
-                       if (retval)
-                               break;
-               } else {
-                       int uncopied;
-                       /* The copy function takes the read lock and handles
-                          locking internally for this case */
-                       uncopied = copy_from_read_buf(tty, &b, &nr);
-                       uncopied += copy_from_read_buf(tty, &b, &nr);
-                       if (uncopied) {
-                               retval = -EFAULT;
-                               break;
-                       }
-               }
-
-               /* If there is enough space in the read buffer now, let the
-                * low-level driver know. We use n_tty_chars_in_buffer() to
-                * check the buffer, as it now knows about canonical mode.
-                * Otherwise, if the driver is throttled and the line is
-                * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
-                * we won't get any more characters.
-                */
-               if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
-                       n_tty_set_room(tty);
-                       check_unthrottle(tty);
-               }
-
-               if (b - buf >= minimum)
-                       break;
-               if (time)
-                       timeout = time;
-       }
-       mutex_unlock(&tty->atomic_read_lock);
-       remove_wait_queue(&tty->read_wait, &wait);
-
-       if (!waitqueue_active(&tty->read_wait))
-               tty->minimum_to_wake = minimum;
-
-       __set_current_state(TASK_RUNNING);
-       size = b - buf;
-       if (size) {
-               retval = size;
-               if (nr)
-                       clear_bit(TTY_PUSH, &tty->flags);
-       } else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
-                goto do_it_again;
-
-       n_tty_set_room(tty);
-       return retval;
-}
-
-/**
- *     n_tty_write             -       write function for tty
- *     @tty: tty device
- *     @file: file object
- *     @buf: userspace buffer pointer
- *     @nr: size of I/O
- *
- *     Write function of the terminal device.  This is serialized with
- *     respect to other write callers but not to termios changes, reads
- *     and other such events.  Since the receive code will echo characters,
- *     thus calling driver write methods, the output_lock is used in
- *     the output processing functions called here as well as in the
- *     echo processing function to protect the column state and space
- *     left in the buffer.
- *
- *     This code must be sure never to sleep through a hangup.
- *
- *     Locking: output_lock to protect column state and space left
- *              (note that the process_output*() functions take this
- *               lock themselves)
- */
-
-static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
-                          const unsigned char *buf, size_t nr)
-{
-       const unsigned char *b = buf;
-       DECLARE_WAITQUEUE(wait, current);
-       int c;
-       ssize_t retval = 0;
-
-       /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
-       if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) {
-               retval = tty_check_change(tty);
-               if (retval)
-                       return retval;
-       }
-
-       /* Write out any echoed characters that are still pending */
-       process_echoes(tty);
-
-       add_wait_queue(&tty->write_wait, &wait);
-       while (1) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
-                       retval = -EIO;
-                       break;
-               }
-               if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
-                       while (nr > 0) {
-                               ssize_t num = process_output_block(tty, b, nr);
-                               if (num < 0) {
-                                       if (num == -EAGAIN)
-                                               break;
-                                       retval = num;
-                                       goto break_out;
-                               }
-                               b += num;
-                               nr -= num;
-                               if (nr == 0)
-                                       break;
-                               c = *b;
-                               if (process_output(c, tty) < 0)
-                                       break;
-                               b++; nr--;
-                       }
-                       if (tty->ops->flush_chars)
-                               tty->ops->flush_chars(tty);
-               } else {
-                       while (nr > 0) {
-                               c = tty->ops->write(tty, b, nr);
-                               if (c < 0) {
-                                       retval = c;
-                                       goto break_out;
-                               }
-                               if (!c)
-                                       break;
-                               b += c;
-                               nr -= c;
-                       }
-               }
-               if (!nr)
-                       break;
-               if (file->f_flags & O_NONBLOCK) {
-                       retval = -EAGAIN;
-                       break;
-               }
-               schedule();
-       }
-break_out:
-       __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&tty->write_wait, &wait);
-       if (b - buf != nr && tty->fasync)
-               set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-       return (b - buf) ? b - buf : retval;
-}
-
-/**
- *     n_tty_poll              -       poll method for N_TTY
- *     @tty: terminal device
- *     @file: file accessing it
- *     @wait: poll table
- *
- *     Called when the line discipline is asked to poll() for data or
- *     for special events. This code is not serialized with respect to
- *     other events save open/close.
- *
- *     This code must be sure never to sleep through a hangup.
- *     Called without the kernel lock held - fine
- */
-
-static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
-                                                       poll_table *wait)
-{
-       unsigned int mask = 0;
-
-       poll_wait(file, &tty->read_wait, wait);
-       poll_wait(file, &tty->write_wait, wait);
-       if (input_available_p(tty, TIME_CHAR(tty) ? 0 : MIN_CHAR(tty)))
-               mask |= POLLIN | POLLRDNORM;
-       if (tty->packet && tty->link->ctrl_status)
-               mask |= POLLPRI | POLLIN | POLLRDNORM;
-       if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
-               mask |= POLLHUP;
-       if (tty_hung_up_p(file))
-               mask |= POLLHUP;
-       if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {
-               if (MIN_CHAR(tty) && !TIME_CHAR(tty))
-                       tty->minimum_to_wake = MIN_CHAR(tty);
-               else
-                       tty->minimum_to_wake = 1;
-       }
-       if (tty->ops->write && !tty_is_writelocked(tty) &&
-                       tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
-                       tty_write_room(tty) > 0)
-               mask |= POLLOUT | POLLWRNORM;
-       return mask;
-}
-
-static unsigned long inq_canon(struct tty_struct *tty)
-{
-       int nr, head, tail;
-
-       if (!tty->canon_data)
-               return 0;
-       head = tty->canon_head;
-       tail = tty->read_tail;
-       nr = (head - tail) & (N_TTY_BUF_SIZE-1);
-       /* Skip EOF-chars.. */
-       while (head != tail) {
-               if (test_bit(tail, tty->read_flags) &&
-                   tty->read_buf[tail] == __DISABLED_CHAR)
-                       nr--;
-               tail = (tail+1) & (N_TTY_BUF_SIZE-1);
-       }
-       return nr;
-}
-
-static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       int retval;
-
-       switch (cmd) {
-       case TIOCOUTQ:
-               return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
-       case TIOCINQ:
-               /* FIXME: Locking */
-               retval = tty->read_cnt;
-               if (L_ICANON(tty))
-                       retval = inq_canon(tty);
-               return put_user(retval, (unsigned int __user *) arg);
-       default:
-               return n_tty_ioctl_helper(tty, file, cmd, arg);
-       }
-}
-
-struct tty_ldisc_ops tty_ldisc_N_TTY = {
-       .magic           = TTY_LDISC_MAGIC,
-       .name            = "n_tty",
-       .open            = n_tty_open,
-       .close           = n_tty_close,
-       .flush_buffer    = n_tty_flush_buffer,
-       .chars_in_buffer = n_tty_chars_in_buffer,
-       .read            = n_tty_read,
-       .write           = n_tty_write,
-       .ioctl           = n_tty_ioctl,
-       .set_termios     = n_tty_set_termios,
-       .poll            = n_tty_poll,
-       .receive_buf     = n_tty_receive_buf,
-       .write_wakeup    = n_tty_write_wakeup
-};
-
-/**
- *     n_tty_inherit_ops       -       inherit N_TTY methods
- *     @ops: struct tty_ldisc_ops where to save N_TTY methods
- *
- *     Used by a generic struct tty_ldisc_ops to easily inherit N_TTY
- *     methods.
- */
-
-void n_tty_inherit_ops(struct tty_ldisc_ops *ops)
-{
-       *ops = tty_ldisc_N_TTY;
-       ops->owner = NULL;
-       ops->refcount = ops->flags = 0;
-}
-EXPORT_SYMBOL_GPL(n_tty_inherit_ops);
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
deleted file mode 100644 (file)
index 923a485..0000000
+++ /dev/null
@@ -1,777 +0,0 @@
-/*
- *  linux/drivers/char/pty.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- *
- *  Added support for a Unix98-style ptmx device.
- *    -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
- *
- *  When reading this code see also fs/devpts. In particular note that the
- *  driver_data field is used by the devpts side as a binding to the devpts
- *  inode.
- */
-
-#include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/sysctl.h>
-#include <linux/device.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/devpts_fs.h>
-#include <linux/slab.h>
-
-#include <asm/system.h>
-
-#ifdef CONFIG_UNIX98_PTYS
-static struct tty_driver *ptm_driver;
-static struct tty_driver *pts_driver;
-#endif
-
-static void pty_close(struct tty_struct *tty, struct file *filp)
-{
-       BUG_ON(!tty);
-       if (tty->driver->subtype == PTY_TYPE_MASTER)
-               WARN_ON(tty->count > 1);
-       else {
-               if (tty->count > 2)
-                       return;
-       }
-       wake_up_interruptible(&tty->read_wait);
-       wake_up_interruptible(&tty->write_wait);
-       tty->packet = 0;
-       if (!tty->link)
-               return;
-       tty->link->packet = 0;
-       set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
-       wake_up_interruptible(&tty->link->read_wait);
-       wake_up_interruptible(&tty->link->write_wait);
-       if (tty->driver->subtype == PTY_TYPE_MASTER) {
-               set_bit(TTY_OTHER_CLOSED, &tty->flags);
-#ifdef CONFIG_UNIX98_PTYS
-               if (tty->driver == ptm_driver)
-                       devpts_pty_kill(tty->link);
-#endif
-               tty_unlock();
-               tty_vhangup(tty->link);
-               tty_lock();
-       }
-}
-
-/*
- * The unthrottle routine is called by the line discipline to signal
- * that it can receive more characters.  For PTY's, the TTY_THROTTLED
- * flag is always set, to force the line discipline to always call the
- * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
- * characters in the queue.  This is necessary since each time this
- * happens, we need to wake up any sleeping processes that could be
- * (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
- * for the pty buffer to be drained.
- */
-static void pty_unthrottle(struct tty_struct *tty)
-{
-       tty_wakeup(tty->link);
-       set_bit(TTY_THROTTLED, &tty->flags);
-}
-
-/**
- *     pty_space       -       report space left for writing
- *     @to: tty we are writing into
- *
- *     The tty buffers allow 64K but we sneak a peak and clip at 8K this
- *     allows a lot of overspill room for echo and other fun messes to
- *     be handled properly
- */
-
-static int pty_space(struct tty_struct *to)
-{
-       int n = 8192 - to->buf.memory_used;
-       if (n < 0)
-               return 0;
-       return n;
-}
-
-/**
- *     pty_write               -       write to a pty
- *     @tty: the tty we write from
- *     @buf: kernel buffer of data
- *     @count: bytes to write
- *
- *     Our "hardware" write method. Data is coming from the ldisc which
- *     may be in a non sleeping state. We simply throw this at the other
- *     end of the link as if we were an IRQ handler receiving stuff for
- *     the other side of the pty/tty pair.
- */
-
-static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
-{
-       struct tty_struct *to = tty->link;
-
-       if (tty->stopped)
-               return 0;
-
-       if (c > 0) {
-               /* Stuff the data into the input queue of the other end */
-               c = tty_insert_flip_string(to, buf, c);
-               /* And shovel */
-               if (c) {
-                       tty_flip_buffer_push(to);
-                       tty_wakeup(tty);
-               }
-       }
-       return c;
-}
-
-/**
- *     pty_write_room  -       write space
- *     @tty: tty we are writing from
- *
- *     Report how many bytes the ldisc can send into the queue for
- *     the other device.
- */
-
-static int pty_write_room(struct tty_struct *tty)
-{
-       if (tty->stopped)
-               return 0;
-       return pty_space(tty->link);
-}
-
-/**
- *     pty_chars_in_buffer     -       characters currently in our tx queue
- *     @tty: our tty
- *
- *     Report how much we have in the transmit queue. As everything is
- *     instantly at the other end this is easy to implement.
- */
-
-static int pty_chars_in_buffer(struct tty_struct *tty)
-{
-       return 0;
-}
-
-/* Set the lock flag on a pty */
-static int pty_set_lock(struct tty_struct *tty, int __user *arg)
-{
-       int val;
-       if (get_user(val, arg))
-               return -EFAULT;
-       if (val)
-               set_bit(TTY_PTY_LOCK, &tty->flags);
-       else
-               clear_bit(TTY_PTY_LOCK, &tty->flags);
-       return 0;
-}
-
-/* Send a signal to the slave */
-static int pty_signal(struct tty_struct *tty, int sig)
-{
-       unsigned long flags;
-       struct pid *pgrp;
-
-       if (tty->link) {
-               spin_lock_irqsave(&tty->link->ctrl_lock, flags);
-               pgrp = get_pid(tty->link->pgrp);
-               spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
-
-               kill_pgrp(pgrp, sig, 1);
-               put_pid(pgrp);
-       }
-       return 0;
-}
-
-static void pty_flush_buffer(struct tty_struct *tty)
-{
-       struct tty_struct *to = tty->link;
-       unsigned long flags;
-
-       if (!to)
-               return;
-       /* tty_buffer_flush(to); FIXME */
-       if (to->packet) {
-               spin_lock_irqsave(&tty->ctrl_lock, flags);
-               tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
-               wake_up_interruptible(&to->read_wait);
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-       }
-}
-
-static int pty_open(struct tty_struct *tty, struct file *filp)
-{
-       int     retval = -ENODEV;
-
-       if (!tty || !tty->link)
-               goto out;
-
-       retval = -EIO;
-       if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
-               goto out;
-       if (test_bit(TTY_PTY_LOCK, &tty->link->flags))
-               goto out;
-       if (tty->link->count != 1)
-               goto out;
-
-       clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
-       set_bit(TTY_THROTTLED, &tty->flags);
-       retval = 0;
-out:
-       return retval;
-}
-
-static void pty_set_termios(struct tty_struct *tty,
-                                       struct ktermios *old_termios)
-{
-       tty->termios->c_cflag &= ~(CSIZE | PARENB);
-       tty->termios->c_cflag |= (CS8 | CREAD);
-}
-
-/**
- *     pty_do_resize           -       resize event
- *     @tty: tty being resized
- *     @ws: window size being set.
- *
- *     Update the termios variables and send the necessary signals to
- *     peform a terminal resize correctly
- */
-
-int pty_resize(struct tty_struct *tty,  struct winsize *ws)
-{
-       struct pid *pgrp, *rpgrp;
-       unsigned long flags;
-       struct tty_struct *pty = tty->link;
-
-       /* For a PTY we need to lock the tty side */
-       mutex_lock(&tty->termios_mutex);
-       if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
-               goto done;
-
-       /* Get the PID values and reference them so we can
-          avoid holding the tty ctrl lock while sending signals.
-          We need to lock these individually however. */
-
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       pgrp = get_pid(tty->pgrp);
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
-       spin_lock_irqsave(&pty->ctrl_lock, flags);
-       rpgrp = get_pid(pty->pgrp);
-       spin_unlock_irqrestore(&pty->ctrl_lock, flags);
-
-       if (pgrp)
-               kill_pgrp(pgrp, SIGWINCH, 1);
-       if (rpgrp != pgrp && rpgrp)
-               kill_pgrp(rpgrp, SIGWINCH, 1);
-
-       put_pid(pgrp);
-       put_pid(rpgrp);
-
-       tty->winsize = *ws;
-       pty->winsize = *ws;     /* Never used so will go away soon */
-done:
-       mutex_unlock(&tty->termios_mutex);
-       return 0;
-}
-
-/* Traditional BSD devices */
-#ifdef CONFIG_LEGACY_PTYS
-
-static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
-{
-       struct tty_struct *o_tty;
-       int idx = tty->index;
-       int retval;
-
-       o_tty = alloc_tty_struct();
-       if (!o_tty)
-               return -ENOMEM;
-       if (!try_module_get(driver->other->owner)) {
-               /* This cannot in fact currently happen */
-               free_tty_struct(o_tty);
-               return -ENOMEM;
-       }
-       initialize_tty_struct(o_tty, driver->other, idx);
-
-       /* We always use new tty termios data so we can do this
-          the easy way .. */
-       retval = tty_init_termios(tty);
-       if (retval)
-               goto free_mem_out;
-
-       retval = tty_init_termios(o_tty);
-       if (retval) {
-               tty_free_termios(tty);
-               goto free_mem_out;
-       }
-
-       /*
-        * Everything allocated ... set up the o_tty structure.
-        */
-       driver->other->ttys[idx] = o_tty;
-       tty_driver_kref_get(driver->other);
-       if (driver->subtype == PTY_TYPE_MASTER)
-               o_tty->count++;
-       /* Establish the links in both directions */
-       tty->link   = o_tty;
-       o_tty->link = tty;
-
-       tty_driver_kref_get(driver);
-       tty->count++;
-       driver->ttys[idx] = tty;
-       return 0;
-free_mem_out:
-       module_put(o_tty->driver->owner);
-       free_tty_struct(o_tty);
-       return -ENOMEM;
-}
-
-static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
-                        unsigned int cmd, unsigned long arg)
-{
-       switch (cmd) {
-       case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
-               return pty_set_lock(tty, (int __user *) arg);
-       case TIOCSIG:    /* Send signal to other side of pty */
-               return pty_signal(tty, (int) arg);
-       }
-       return -ENOIOCTLCMD;
-}
-
-static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
-module_param(legacy_count, int, 0);
-
-/*
- * The master side of a pty can do TIOCSPTLCK and thus
- * has pty_bsd_ioctl.
- */
-static const struct tty_operations master_pty_ops_bsd = {
-       .install = pty_install,
-       .open = pty_open,
-       .close = pty_close,
-       .write = pty_write,
-       .write_room = pty_write_room,
-       .flush_buffer = pty_flush_buffer,
-       .chars_in_buffer = pty_chars_in_buffer,
-       .unthrottle = pty_unthrottle,
-       .set_termios = pty_set_termios,
-       .ioctl = pty_bsd_ioctl,
-       .resize = pty_resize
-};
-
-static const struct tty_operations slave_pty_ops_bsd = {
-       .install = pty_install,
-       .open = pty_open,
-       .close = pty_close,
-       .write = pty_write,
-       .write_room = pty_write_room,
-       .flush_buffer = pty_flush_buffer,
-       .chars_in_buffer = pty_chars_in_buffer,
-       .unthrottle = pty_unthrottle,
-       .set_termios = pty_set_termios,
-       .resize = pty_resize
-};
-
-static void __init legacy_pty_init(void)
-{
-       struct tty_driver *pty_driver, *pty_slave_driver;
-
-       if (legacy_count <= 0)
-               return;
-
-       pty_driver = alloc_tty_driver(legacy_count);
-       if (!pty_driver)
-               panic("Couldn't allocate pty driver");
-
-       pty_slave_driver = alloc_tty_driver(legacy_count);
-       if (!pty_slave_driver)
-               panic("Couldn't allocate pty slave driver");
-
-       pty_driver->owner = THIS_MODULE;
-       pty_driver->driver_name = "pty_master";
-       pty_driver->name = "pty";
-       pty_driver->major = PTY_MASTER_MAJOR;
-       pty_driver->minor_start = 0;
-       pty_driver->type = TTY_DRIVER_TYPE_PTY;
-       pty_driver->subtype = PTY_TYPE_MASTER;
-       pty_driver->init_termios = tty_std_termios;
-       pty_driver->init_termios.c_iflag = 0;
-       pty_driver->init_termios.c_oflag = 0;
-       pty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
-       pty_driver->init_termios.c_lflag = 0;
-       pty_driver->init_termios.c_ispeed = 38400;
-       pty_driver->init_termios.c_ospeed = 38400;
-       pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
-       pty_driver->other = pty_slave_driver;
-       tty_set_operations(pty_driver, &master_pty_ops_bsd);
-
-       pty_slave_driver->owner = THIS_MODULE;
-       pty_slave_driver->driver_name = "pty_slave";
-       pty_slave_driver->name = "ttyp";
-       pty_slave_driver->major = PTY_SLAVE_MAJOR;
-       pty_slave_driver->minor_start = 0;
-       pty_slave_driver->type = TTY_DRIVER_TYPE_PTY;
-       pty_slave_driver->subtype = PTY_TYPE_SLAVE;
-       pty_slave_driver->init_termios = tty_std_termios;
-       pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
-       pty_slave_driver->init_termios.c_ispeed = 38400;
-       pty_slave_driver->init_termios.c_ospeed = 38400;
-       pty_slave_driver->flags = TTY_DRIVER_RESET_TERMIOS |
-                                       TTY_DRIVER_REAL_RAW;
-       pty_slave_driver->other = pty_driver;
-       tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd);
-
-       if (tty_register_driver(pty_driver))
-               panic("Couldn't register pty driver");
-       if (tty_register_driver(pty_slave_driver))
-               panic("Couldn't register pty slave driver");
-}
-#else
-static inline void legacy_pty_init(void) { }
-#endif
-
-/* Unix98 devices */
-#ifdef CONFIG_UNIX98_PTYS
-/*
- * sysctl support for setting limits on the number of Unix98 ptys allocated.
- * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
- */
-int pty_limit = NR_UNIX98_PTY_DEFAULT;
-static int pty_limit_min;
-static int pty_limit_max = NR_UNIX98_PTY_MAX;
-static int pty_count;
-
-static struct cdev ptmx_cdev;
-
-static struct ctl_table pty_table[] = {
-       {
-               .procname       = "max",
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .data           = &pty_limit,
-               .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &pty_limit_min,
-               .extra2         = &pty_limit_max,
-       }, {
-               .procname       = "nr",
-               .maxlen         = sizeof(int),
-               .mode           = 0444,
-               .data           = &pty_count,
-               .proc_handler   = proc_dointvec,
-       }, 
-       {}
-};
-
-static struct ctl_table pty_kern_table[] = {
-       {
-               .procname       = "pty",
-               .mode           = 0555,
-               .child          = pty_table,
-       },
-       {}
-};
-
-static struct ctl_table pty_root_table[] = {
-       {
-               .procname       = "kernel",
-               .mode           = 0555,
-               .child          = pty_kern_table,
-       },
-       {}
-};
-
-
-static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
-                           unsigned int cmd, unsigned long arg)
-{
-       switch (cmd) {
-       case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
-               return pty_set_lock(tty, (int __user *)arg);
-       case TIOCGPTN: /* Get PT Number */
-               return put_user(tty->index, (unsigned int __user *)arg);
-       case TIOCSIG:    /* Send signal to other side of pty */
-               return pty_signal(tty, (int) arg);
-       }
-
-       return -ENOIOCTLCMD;
-}
-
-/**
- *     ptm_unix98_lookup       -       find a pty master
- *     @driver: ptm driver
- *     @idx: tty index
- *
- *     Look up a pty master device. Called under the tty_mutex for now.
- *     This provides our locking.
- */
-
-static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
-               struct inode *ptm_inode, int idx)
-{
-       struct tty_struct *tty = devpts_get_tty(ptm_inode, idx);
-       if (tty)
-               tty = tty->link;
-       return tty;
-}
-
-/**
- *     pts_unix98_lookup       -       find a pty slave
- *     @driver: pts driver
- *     @idx: tty index
- *
- *     Look up a pty master device. Called under the tty_mutex for now.
- *     This provides our locking.
- */
-
-static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
-               struct inode *pts_inode, int idx)
-{
-       struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
-       /* Master must be open before slave */
-       if (!tty)
-               return ERR_PTR(-EIO);
-       return tty;
-}
-
-static void pty_unix98_shutdown(struct tty_struct *tty)
-{
-       /* We have our own method as we don't use the tty index */
-       kfree(tty->termios);
-}
-
-/* We have no need to install and remove our tty objects as devpts does all
-   the work for us */
-
-static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
-{
-       struct tty_struct *o_tty;
-       int idx = tty->index;
-
-       o_tty = alloc_tty_struct();
-       if (!o_tty)
-               return -ENOMEM;
-       if (!try_module_get(driver->other->owner)) {
-               /* This cannot in fact currently happen */
-               free_tty_struct(o_tty);
-               return -ENOMEM;
-       }
-       initialize_tty_struct(o_tty, driver->other, idx);
-
-       tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
-       if (tty->termios == NULL)
-               goto free_mem_out;
-       *tty->termios = driver->init_termios;
-       tty->termios_locked = tty->termios + 1;
-
-       o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
-       if (o_tty->termios == NULL)
-               goto free_mem_out;
-       *o_tty->termios = driver->other->init_termios;
-       o_tty->termios_locked = o_tty->termios + 1;
-
-       tty_driver_kref_get(driver->other);
-       if (driver->subtype == PTY_TYPE_MASTER)
-               o_tty->count++;
-       /* Establish the links in both directions */
-       tty->link   = o_tty;
-       o_tty->link = tty;
-       /*
-        * All structures have been allocated, so now we install them.
-        * Failures after this point use release_tty to clean up, so
-        * there's no need to null out the local pointers.
-        */
-       tty_driver_kref_get(driver);
-       tty->count++;
-       pty_count++;
-       return 0;
-free_mem_out:
-       kfree(o_tty->termios);
-       module_put(o_tty->driver->owner);
-       free_tty_struct(o_tty);
-       kfree(tty->termios);
-       return -ENOMEM;
-}
-
-static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
-{
-       pty_count--;
-}
-
-static const struct tty_operations ptm_unix98_ops = {
-       .lookup = ptm_unix98_lookup,
-       .install = pty_unix98_install,
-       .remove = pty_unix98_remove,
-       .open = pty_open,
-       .close = pty_close,
-       .write = pty_write,
-       .write_room = pty_write_room,
-       .flush_buffer = pty_flush_buffer,
-       .chars_in_buffer = pty_chars_in_buffer,
-       .unthrottle = pty_unthrottle,
-       .set_termios = pty_set_termios,
-       .ioctl = pty_unix98_ioctl,
-       .shutdown = pty_unix98_shutdown,
-       .resize = pty_resize
-};
-
-static const struct tty_operations pty_unix98_ops = {
-       .lookup = pts_unix98_lookup,
-       .install = pty_unix98_install,
-       .remove = pty_unix98_remove,
-       .open = pty_open,
-       .close = pty_close,
-       .write = pty_write,
-       .write_room = pty_write_room,
-       .flush_buffer = pty_flush_buffer,
-       .chars_in_buffer = pty_chars_in_buffer,
-       .unthrottle = pty_unthrottle,
-       .set_termios = pty_set_termios,
-       .shutdown = pty_unix98_shutdown
-};
-
-/**
- *     ptmx_open               -       open a unix 98 pty master
- *     @inode: inode of device file
- *     @filp: file pointer to tty
- *
- *     Allocate a unix98 pty master device from the ptmx driver.
- *
- *     Locking: tty_mutex protects the init_dev work. tty->count should
- *             protect the rest.
- *             allocated_ptys_lock handles the list of free pty numbers
- */
-
-static int ptmx_open(struct inode *inode, struct file *filp)
-{
-       struct tty_struct *tty;
-       int retval;
-       int index;
-
-       nonseekable_open(inode, filp);
-
-       /* find a device that is not in use. */
-       tty_lock();
-       index = devpts_new_index(inode);
-       tty_unlock();
-       if (index < 0)
-               return index;
-
-       mutex_lock(&tty_mutex);
-       tty_lock();
-       tty = tty_init_dev(ptm_driver, index, 1);
-       mutex_unlock(&tty_mutex);
-
-       if (IS_ERR(tty)) {
-               retval = PTR_ERR(tty);
-               goto out;
-       }
-
-       set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
-
-       retval = tty_add_file(tty, filp);
-       if (retval)
-               goto out;
-
-       retval = devpts_pty_new(inode, tty->link);
-       if (retval)
-               goto out1;
-
-       retval = ptm_driver->ops->open(tty, filp);
-       if (retval)
-               goto out2;
-out1:
-       tty_unlock();
-       return retval;
-out2:
-       tty_unlock();
-       tty_release(inode, filp);
-       return retval;
-out:
-       devpts_kill_index(inode, index);
-       tty_unlock();
-       return retval;
-}
-
-static struct file_operations ptmx_fops;
-
-static void __init unix98_pty_init(void)
-{
-       ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
-       if (!ptm_driver)
-               panic("Couldn't allocate Unix98 ptm driver");
-       pts_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
-       if (!pts_driver)
-               panic("Couldn't allocate Unix98 pts driver");
-
-       ptm_driver->owner = THIS_MODULE;
-       ptm_driver->driver_name = "pty_master";
-       ptm_driver->name = "ptm";
-       ptm_driver->major = UNIX98_PTY_MASTER_MAJOR;
-       ptm_driver->minor_start = 0;
-       ptm_driver->type = TTY_DRIVER_TYPE_PTY;
-       ptm_driver->subtype = PTY_TYPE_MASTER;
-       ptm_driver->init_termios = tty_std_termios;
-       ptm_driver->init_termios.c_iflag = 0;
-       ptm_driver->init_termios.c_oflag = 0;
-       ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
-       ptm_driver->init_termios.c_lflag = 0;
-       ptm_driver->init_termios.c_ispeed = 38400;
-       ptm_driver->init_termios.c_ospeed = 38400;
-       ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
-               TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
-       ptm_driver->other = pts_driver;
-       tty_set_operations(ptm_driver, &ptm_unix98_ops);
-
-       pts_driver->owner = THIS_MODULE;
-       pts_driver->driver_name = "pty_slave";
-       pts_driver->name = "pts";
-       pts_driver->major = UNIX98_PTY_SLAVE_MAJOR;
-       pts_driver->minor_start = 0;
-       pts_driver->type = TTY_DRIVER_TYPE_PTY;
-       pts_driver->subtype = PTY_TYPE_SLAVE;
-       pts_driver->init_termios = tty_std_termios;
-       pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
-       pts_driver->init_termios.c_ispeed = 38400;
-       pts_driver->init_termios.c_ospeed = 38400;
-       pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
-               TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
-       pts_driver->other = ptm_driver;
-       tty_set_operations(pts_driver, &pty_unix98_ops);
-
-       if (tty_register_driver(ptm_driver))
-               panic("Couldn't register Unix98 ptm driver");
-       if (tty_register_driver(pts_driver))
-               panic("Couldn't register Unix98 pts driver");
-
-       register_sysctl_table(pty_root_table);
-
-       /* Now create the /dev/ptmx special device */
-       tty_default_fops(&ptmx_fops);
-       ptmx_fops.open = ptmx_open;
-
-       cdev_init(&ptmx_cdev, &ptmx_fops);
-       if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
-           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
-               panic("Couldn't register /dev/ptmx driver\n");
-       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
-}
-
-#else
-static inline void unix98_pty_init(void) { }
-#endif
-
-static int __init pty_init(void)
-{
-       legacy_pty_init();
-       unix98_pty_init();
-       return 0;
-}
-module_init(pty_init);
diff --git a/drivers/char/selection.c b/drivers/char/selection.c
deleted file mode 100644 (file)
index ebae344..0000000
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- * linux/drivers/char/selection.c
- *
- * This module exports the functions:
- *
- *     'int set_selection(struct tiocl_selection __user *, struct tty_struct *)'
- *     'void clear_selection(void)'
- *     'int paste_selection(struct tty_struct *)'
- *     'int sel_loadlut(char __user *)'
- *
- * Now that /dev/vcs exists, most of this can disappear again.
- */
-
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-
-#include <asm/uaccess.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/consolemap.h>
-#include <linux/selection.h>
-#include <linux/tiocl.h>
-#include <linux/console.h>
-#include <linux/smp_lock.h>
-
-/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
-#define isspace(c)     ((c) == ' ')
-
-extern void poke_blanked_console(void);
-
-/* Variables for selection control. */
-/* Use a dynamic buffer, instead of static (Dec 1994) */
-struct vc_data *sel_cons;              /* must not be deallocated */
-static int use_unicode;
-static volatile int sel_start = -1;    /* cleared by clear_selection */
-static int sel_end;
-static int sel_buffer_lth;
-static char *sel_buffer;
-
-/* clear_selection, highlight and highlight_pointer can be called
-   from interrupt (via scrollback/front) */
-
-/* set reverse video on characters s-e of console with selection. */
-static inline void highlight(const int s, const int e)
-{
-       invert_screen(sel_cons, s, e-s+2, 1);
-}
-
-/* use complementary color to show the pointer */
-static inline void highlight_pointer(const int where)
-{
-       complement_pos(sel_cons, where);
-}
-
-static u16
-sel_pos(int n)
-{
-       return inverse_translate(sel_cons, screen_glyph(sel_cons, n),
-                               use_unicode);
-}
-
-/* remove the current selection highlight, if any,
-   from the console holding the selection. */
-void
-clear_selection(void) {
-       highlight_pointer(-1); /* hide the pointer */
-       if (sel_start != -1) {
-               highlight(sel_start, sel_end);
-               sel_start = -1;
-       }
-}
-
-/*
- * User settable table: what characters are to be considered alphabetic?
- * 256 bits
- */
-static u32 inwordLut[8]={
-  0x00000000, /* control chars     */
-  0x03FF0000, /* digits            */
-  0x87FFFFFE, /* uppercase and '_' */
-  0x07FFFFFE, /* lowercase         */
-  0x00000000,
-  0x00000000,
-  0xFF7FFFFF, /* latin-1 accented letters, not multiplication sign */
-  0xFF7FFFFF  /* latin-1 accented letters, not division sign */
-};
-
-static inline int inword(const u16 c) {
-       return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1);
-}
-
-/* set inwordLut contents. Invoked by ioctl(). */
-int sel_loadlut(char __user *p)
-{
-       return copy_from_user(inwordLut, (u32 __user *)(p+4), 32) ? -EFAULT : 0;
-}
-
-/* does screen address p correspond to character at LH/RH edge of screen? */
-static inline int atedge(const int p, int size_row)
-{
-       return (!(p % size_row) || !((p + 2) % size_row));
-}
-
-/* constrain v such that v <= u */
-static inline unsigned short limit(const unsigned short v, const unsigned short u)
-{
-       return (v > u) ? u : v;
-}
-
-/* stores the char in UTF8 and returns the number of bytes used (1-3) */
-static int store_utf8(u16 c, char *p)
-{
-       if (c < 0x80) {
-               /*  0******* */
-               p[0] = c;
-               return 1;
-       } else if (c < 0x800) {
-               /* 110***** 10****** */
-               p[0] = 0xc0 | (c >> 6);
-               p[1] = 0x80 | (c & 0x3f);
-               return 2;
-       } else {
-               /* 1110**** 10****** 10****** */
-               p[0] = 0xe0 | (c >> 12);
-               p[1] = 0x80 | ((c >> 6) & 0x3f);
-               p[2] = 0x80 | (c & 0x3f);
-               return 3;
-       }
-}
-
-/* set the current selection. Invoked by ioctl() or by kernel code. */
-int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty)
-{
-       struct vc_data *vc = vc_cons[fg_console].d;
-       int sel_mode, new_sel_start, new_sel_end, spc;
-       char *bp, *obp;
-       int i, ps, pe, multiplier;
-       u16 c;
-       struct kbd_struct *kbd = kbd_table + fg_console;
-
-       poke_blanked_console();
-
-       { unsigned short xs, ys, xe, ye;
-
-         if (!access_ok(VERIFY_READ, sel, sizeof(*sel)))
-               return -EFAULT;
-         __get_user(xs, &sel->xs);
-         __get_user(ys, &sel->ys);
-         __get_user(xe, &sel->xe);
-         __get_user(ye, &sel->ye);
-         __get_user(sel_mode, &sel->sel_mode);
-         xs--; ys--; xe--; ye--;
-         xs = limit(xs, vc->vc_cols - 1);
-         ys = limit(ys, vc->vc_rows - 1);
-         xe = limit(xe, vc->vc_cols - 1);
-         ye = limit(ye, vc->vc_rows - 1);
-         ps = ys * vc->vc_size_row + (xs << 1);
-         pe = ye * vc->vc_size_row + (xe << 1);
-
-         if (sel_mode == TIOCL_SELCLEAR) {
-             /* useful for screendump without selection highlights */
-             clear_selection();
-             return 0;
-         }
-
-         if (mouse_reporting() && (sel_mode & TIOCL_SELMOUSEREPORT)) {
-             mouse_report(tty, sel_mode & TIOCL_SELBUTTONMASK, xs, ys);
-             return 0;
-         }
-        }
-
-       if (ps > pe)    /* make sel_start <= sel_end */
-       {
-               int tmp = ps;
-               ps = pe;
-               pe = tmp;
-       }
-
-       if (sel_cons != vc_cons[fg_console].d) {
-               clear_selection();
-               sel_cons = vc_cons[fg_console].d;
-       }
-       use_unicode = kbd && kbd->kbdmode == VC_UNICODE;
-
-       switch (sel_mode)
-       {
-               case TIOCL_SELCHAR:     /* character-by-character selection */
-                       new_sel_start = ps;
-                       new_sel_end = pe;
-                       break;
-               case TIOCL_SELWORD:     /* word-by-word selection */
-                       spc = isspace(sel_pos(ps));
-                       for (new_sel_start = ps; ; ps -= 2)
-                       {
-                               if ((spc && !isspace(sel_pos(ps))) ||
-                                   (!spc && !inword(sel_pos(ps))))
-                                       break;
-                               new_sel_start = ps;
-                               if (!(ps % vc->vc_size_row))
-                                       break;
-                       }
-                       spc = isspace(sel_pos(pe));
-                       for (new_sel_end = pe; ; pe += 2)
-                       {
-                               if ((spc && !isspace(sel_pos(pe))) ||
-                                   (!spc && !inword(sel_pos(pe))))
-                                       break;
-                               new_sel_end = pe;
-                               if (!((pe + 2) % vc->vc_size_row))
-                                       break;
-                       }
-                       break;
-               case TIOCL_SELLINE:     /* line-by-line selection */
-                       new_sel_start = ps - ps % vc->vc_size_row;
-                       new_sel_end = pe + vc->vc_size_row
-                                   - pe % vc->vc_size_row - 2;
-                       break;
-               case TIOCL_SELPOINTER:
-                       highlight_pointer(pe);
-                       return 0;
-               default:
-                       return -EINVAL;
-       }
-
-       /* remove the pointer */
-       highlight_pointer(-1);
-
-       /* select to end of line if on trailing space */
-       if (new_sel_end > new_sel_start &&
-               !atedge(new_sel_end, vc->vc_size_row) &&
-               isspace(sel_pos(new_sel_end))) {
-               for (pe = new_sel_end + 2; ; pe += 2)
-                       if (!isspace(sel_pos(pe)) ||
-                           atedge(pe, vc->vc_size_row))
-                               break;
-               if (isspace(sel_pos(pe)))
-                       new_sel_end = pe;
-       }
-       if (sel_start == -1)    /* no current selection */
-               highlight(new_sel_start, new_sel_end);
-       else if (new_sel_start == sel_start)
-       {
-               if (new_sel_end == sel_end)     /* no action required */
-                       return 0;
-               else if (new_sel_end > sel_end) /* extend to right */
-                       highlight(sel_end + 2, new_sel_end);
-               else                            /* contract from right */
-                       highlight(new_sel_end + 2, sel_end);
-       }
-       else if (new_sel_end == sel_end)
-       {
-               if (new_sel_start < sel_start)  /* extend to left */
-                       highlight(new_sel_start, sel_start - 2);
-               else                            /* contract from left */
-                       highlight(sel_start, new_sel_start - 2);
-       }
-       else    /* some other case; start selection from scratch */
-       {
-               clear_selection();
-               highlight(new_sel_start, new_sel_end);
-       }
-       sel_start = new_sel_start;
-       sel_end = new_sel_end;
-
-       /* Allocate a new buffer before freeing the old one ... */
-       multiplier = use_unicode ? 3 : 1;  /* chars can take up to 3 bytes */
-       bp = kmalloc(((sel_end-sel_start)/2+1)*multiplier, GFP_KERNEL);
-       if (!bp) {
-               printk(KERN_WARNING "selection: kmalloc() failed\n");
-               clear_selection();
-               return -ENOMEM;
-       }
-       kfree(sel_buffer);
-       sel_buffer = bp;
-
-       obp = bp;
-       for (i = sel_start; i <= sel_end; i += 2) {
-               c = sel_pos(i);
-               if (use_unicode)
-                       bp += store_utf8(c, bp);
-               else
-                       *bp++ = c;
-               if (!isspace(c))
-                       obp = bp;
-               if (! ((i + 2) % vc->vc_size_row)) {
-                       /* strip trailing blanks from line and add newline,
-                          unless non-space at end of line. */
-                       if (obp != bp) {
-                               bp = obp;
-                               *bp++ = '\r';
-                       }
-                       obp = bp;
-               }
-       }
-       sel_buffer_lth = bp - sel_buffer;
-       return 0;
-}
-
-/* Insert the contents of the selection buffer into the
- * queue of the tty associated with the current console.
- * Invoked by ioctl().
- */
-int paste_selection(struct tty_struct *tty)
-{
-       struct vc_data *vc = tty->driver_data;
-       int     pasted = 0;
-       unsigned int count;
-       struct  tty_ldisc *ld;
-       DECLARE_WAITQUEUE(wait, current);
-
-       /* always called with BTM from vt_ioctl */
-       WARN_ON(!tty_locked());
-
-       acquire_console_sem();
-       poke_blanked_console();
-       release_console_sem();
-
-       ld = tty_ldisc_ref(tty);
-       if (!ld) {
-               tty_unlock();
-               ld = tty_ldisc_ref_wait(tty);
-               tty_lock();
-       }
-
-       add_wait_queue(&vc->paste_wait, &wait);
-       while (sel_buffer && sel_buffer_lth > pasted) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (test_bit(TTY_THROTTLED, &tty->flags)) {
-                       schedule();
-                       continue;
-               }
-               count = sel_buffer_lth - pasted;
-               count = min(count, tty->receive_room);
-               tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
-                                                               NULL, count);
-               pasted += count;
-       }
-       remove_wait_queue(&vc->paste_wait, &wait);
-       __set_current_state(TASK_RUNNING);
-
-       tty_ldisc_deref(ld);
-       return 0;
-}
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
deleted file mode 100644 (file)
index eaa5d3e..0000000
+++ /dev/null
@@ -1,811 +0,0 @@
-/*
- *     Linux Magic System Request Key Hacks
- *
- *     (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- *     based on ideas by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>
- *
- *     (c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
- *     overhauled to use key registration
- *     based upon discusions in irc://irc.openprojects.net/#kernelnewbies
- *
- *     Copyright (c) 2010 Dmitry Torokhov
- *     Input handler conversion
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/kdev_t.h>
-#include <linux/major.h>
-#include <linux/reboot.h>
-#include <linux/sysrq.h>
-#include <linux/kbd_kern.h>
-#include <linux/proc_fs.h>
-#include <linux/nmi.h>
-#include <linux/quotaops.h>
-#include <linux/perf_event.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/suspend.h>
-#include <linux/writeback.h>
-#include <linux/buffer_head.h>         /* for fsync_bdev() */
-#include <linux/swap.h>
-#include <linux/spinlock.h>
-#include <linux/vt_kern.h>
-#include <linux/workqueue.h>
-#include <linux/hrtimer.h>
-#include <linux/oom.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-
-#include <asm/ptrace.h>
-#include <asm/irq_regs.h>
-
-/* Whether we react on sysrq keys or just ignore them */
-static int __read_mostly sysrq_enabled = 1;
-static bool __read_mostly sysrq_always_enabled;
-
-static bool sysrq_on(void)
-{
-       return sysrq_enabled || sysrq_always_enabled;
-}
-
-/*
- * A value of 1 means 'all', other nonzero values are an op mask:
- */
-static bool sysrq_on_mask(int mask)
-{
-       return sysrq_always_enabled ||
-              sysrq_enabled == 1 ||
-              (sysrq_enabled & mask);
-}
-
-static int __init sysrq_always_enabled_setup(char *str)
-{
-       sysrq_always_enabled = true;
-       pr_info("sysrq always enabled.\n");
-
-       return 1;
-}
-
-__setup("sysrq_always_enabled", sysrq_always_enabled_setup);
-
-
-static void sysrq_handle_loglevel(int key)
-{
-       int i;
-
-       i = key - '0';
-       console_loglevel = 7;
-       printk("Loglevel set to %d\n", i);
-       console_loglevel = i;
-}
-static struct sysrq_key_op sysrq_loglevel_op = {
-       .handler        = sysrq_handle_loglevel,
-       .help_msg       = "loglevel(0-9)",
-       .action_msg     = "Changing Loglevel",
-       .enable_mask    = SYSRQ_ENABLE_LOG,
-};
-
-#ifdef CONFIG_VT
-static void sysrq_handle_SAK(int key)
-{
-       struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
-       schedule_work(SAK_work);
-}
-static struct sysrq_key_op sysrq_SAK_op = {
-       .handler        = sysrq_handle_SAK,
-       .help_msg       = "saK",
-       .action_msg     = "SAK",
-       .enable_mask    = SYSRQ_ENABLE_KEYBOARD,
-};
-#else
-#define sysrq_SAK_op (*(struct sysrq_key_op *)NULL)
-#endif
-
-#ifdef CONFIG_VT
-static void sysrq_handle_unraw(int key)
-{
-       struct kbd_struct *kbd = &kbd_table[fg_console];
-
-       if (kbd)
-               kbd->kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
-}
-static struct sysrq_key_op sysrq_unraw_op = {
-       .handler        = sysrq_handle_unraw,
-       .help_msg       = "unRaw",
-       .action_msg     = "Keyboard mode set to system default",
-       .enable_mask    = SYSRQ_ENABLE_KEYBOARD,
-};
-#else
-#define sysrq_unraw_op (*(struct sysrq_key_op *)NULL)
-#endif /* CONFIG_VT */
-
-static void sysrq_handle_crash(int key)
-{
-       char *killer = NULL;
-
-       panic_on_oops = 1;      /* force panic */
-       wmb();
-       *killer = 1;
-}
-static struct sysrq_key_op sysrq_crash_op = {
-       .handler        = sysrq_handle_crash,
-       .help_msg       = "Crash",
-       .action_msg     = "Trigger a crash",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-
-static void sysrq_handle_reboot(int key)
-{
-       lockdep_off();
-       local_irq_enable();
-       emergency_restart();
-}
-static struct sysrq_key_op sysrq_reboot_op = {
-       .handler        = sysrq_handle_reboot,
-       .help_msg       = "reBoot",
-       .action_msg     = "Resetting",
-       .enable_mask    = SYSRQ_ENABLE_BOOT,
-};
-
-static void sysrq_handle_sync(int key)
-{
-       emergency_sync();
-}
-static struct sysrq_key_op sysrq_sync_op = {
-       .handler        = sysrq_handle_sync,
-       .help_msg       = "Sync",
-       .action_msg     = "Emergency Sync",
-       .enable_mask    = SYSRQ_ENABLE_SYNC,
-};
-
-static void sysrq_handle_show_timers(int key)
-{
-       sysrq_timer_list_show();
-}
-
-static struct sysrq_key_op sysrq_show_timers_op = {
-       .handler        = sysrq_handle_show_timers,
-       .help_msg       = "show-all-timers(Q)",
-       .action_msg     = "Show clockevent devices & pending hrtimers (no others)",
-};
-
-static void sysrq_handle_mountro(int key)
-{
-       emergency_remount();
-}
-static struct sysrq_key_op sysrq_mountro_op = {
-       .handler        = sysrq_handle_mountro,
-       .help_msg       = "Unmount",
-       .action_msg     = "Emergency Remount R/O",
-       .enable_mask    = SYSRQ_ENABLE_REMOUNT,
-};
-
-#ifdef CONFIG_LOCKDEP
-static void sysrq_handle_showlocks(int key)
-{
-       debug_show_all_locks();
-}
-
-static struct sysrq_key_op sysrq_showlocks_op = {
-       .handler        = sysrq_handle_showlocks,
-       .help_msg       = "show-all-locks(D)",
-       .action_msg     = "Show Locks Held",
-};
-#else
-#define sysrq_showlocks_op (*(struct sysrq_key_op *)NULL)
-#endif
-
-#ifdef CONFIG_SMP
-static DEFINE_SPINLOCK(show_lock);
-
-static void showacpu(void *dummy)
-{
-       unsigned long flags;
-
-       /* Idle CPUs have no interesting backtrace. */
-       if (idle_cpu(smp_processor_id()))
-               return;
-
-       spin_lock_irqsave(&show_lock, flags);
-       printk(KERN_INFO "CPU%d:\n", smp_processor_id());
-       show_stack(NULL, NULL);
-       spin_unlock_irqrestore(&show_lock, flags);
-}
-
-static void sysrq_showregs_othercpus(struct work_struct *dummy)
-{
-       smp_call_function(showacpu, NULL, 0);
-}
-
-static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus);
-
-static void sysrq_handle_showallcpus(int key)
-{
-       /*
-        * Fall back to the workqueue based printing if the
-        * backtrace printing did not succeed or the
-        * architecture has no support for it:
-        */
-       if (!trigger_all_cpu_backtrace()) {
-               struct pt_regs *regs = get_irq_regs();
-
-               if (regs) {
-                       printk(KERN_INFO "CPU%d:\n", smp_processor_id());
-                       show_regs(regs);
-               }
-               schedule_work(&sysrq_showallcpus);
-       }
-}
-
-static struct sysrq_key_op sysrq_showallcpus_op = {
-       .handler        = sysrq_handle_showallcpus,
-       .help_msg       = "show-backtrace-all-active-cpus(L)",
-       .action_msg     = "Show backtrace of all active CPUs",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-#endif
-
-static void sysrq_handle_showregs(int key)
-{
-       struct pt_regs *regs = get_irq_regs();
-       if (regs)
-               show_regs(regs);
-       perf_event_print_debug();
-}
-static struct sysrq_key_op sysrq_showregs_op = {
-       .handler        = sysrq_handle_showregs,
-       .help_msg       = "show-registers(P)",
-       .action_msg     = "Show Regs",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-
-static void sysrq_handle_showstate(int key)
-{
-       show_state();
-}
-static struct sysrq_key_op sysrq_showstate_op = {
-       .handler        = sysrq_handle_showstate,
-       .help_msg       = "show-task-states(T)",
-       .action_msg     = "Show State",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-
-static void sysrq_handle_showstate_blocked(int key)
-{
-       show_state_filter(TASK_UNINTERRUPTIBLE);
-}
-static struct sysrq_key_op sysrq_showstate_blocked_op = {
-       .handler        = sysrq_handle_showstate_blocked,
-       .help_msg       = "show-blocked-tasks(W)",
-       .action_msg     = "Show Blocked State",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-
-#ifdef CONFIG_TRACING
-#include <linux/ftrace.h>
-
-static void sysrq_ftrace_dump(int key)
-{
-       ftrace_dump(DUMP_ALL);
-}
-static struct sysrq_key_op sysrq_ftrace_dump_op = {
-       .handler        = sysrq_ftrace_dump,
-       .help_msg       = "dump-ftrace-buffer(Z)",
-       .action_msg     = "Dump ftrace buffer",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-#else
-#define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)NULL)
-#endif
-
-static void sysrq_handle_showmem(int key)
-{
-       show_mem();
-}
-static struct sysrq_key_op sysrq_showmem_op = {
-       .handler        = sysrq_handle_showmem,
-       .help_msg       = "show-memory-usage(M)",
-       .action_msg     = "Show Memory",
-       .enable_mask    = SYSRQ_ENABLE_DUMP,
-};
-
-/*
- * Signal sysrq helper function.  Sends a signal to all user processes.
- */
-static void send_sig_all(int sig)
-{
-       struct task_struct *p;
-
-       for_each_process(p) {
-               if (p->mm && !is_global_init(p))
-                       /* Not swapper, init nor kernel thread */
-                       force_sig(sig, p);
-       }
-}
-
-static void sysrq_handle_term(int key)
-{
-       send_sig_all(SIGTERM);
-       console_loglevel = 8;
-}
-static struct sysrq_key_op sysrq_term_op = {
-       .handler        = sysrq_handle_term,
-       .help_msg       = "terminate-all-tasks(E)",
-       .action_msg     = "Terminate All Tasks",
-       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
-};
-
-static void moom_callback(struct work_struct *ignored)
-{
-       out_of_memory(node_zonelist(0, GFP_KERNEL), GFP_KERNEL, 0, NULL);
-}
-
-static DECLARE_WORK(moom_work, moom_callback);
-
-static void sysrq_handle_moom(int key)
-{
-       schedule_work(&moom_work);
-}
-static struct sysrq_key_op sysrq_moom_op = {
-       .handler        = sysrq_handle_moom,
-       .help_msg       = "memory-full-oom-kill(F)",
-       .action_msg     = "Manual OOM execution",
-       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
-};
-
-#ifdef CONFIG_BLOCK
-static void sysrq_handle_thaw(int key)
-{
-       emergency_thaw_all();
-}
-static struct sysrq_key_op sysrq_thaw_op = {
-       .handler        = sysrq_handle_thaw,
-       .help_msg       = "thaw-filesystems(J)",
-       .action_msg     = "Emergency Thaw of all frozen filesystems",
-       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
-};
-#endif
-
-static void sysrq_handle_kill(int key)
-{
-       send_sig_all(SIGKILL);
-       console_loglevel = 8;
-}
-static struct sysrq_key_op sysrq_kill_op = {
-       .handler        = sysrq_handle_kill,
-       .help_msg       = "kill-all-tasks(I)",
-       .action_msg     = "Kill All Tasks",
-       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
-};
-
-static void sysrq_handle_unrt(int key)
-{
-       normalize_rt_tasks();
-}
-static struct sysrq_key_op sysrq_unrt_op = {
-       .handler        = sysrq_handle_unrt,
-       .help_msg       = "nice-all-RT-tasks(N)",
-       .action_msg     = "Nice All RT Tasks",
-       .enable_mask    = SYSRQ_ENABLE_RTNICE,
-};
-
-/* Key Operations table and lock */
-static DEFINE_SPINLOCK(sysrq_key_table_lock);
-
-static struct sysrq_key_op *sysrq_key_table[36] = {
-       &sysrq_loglevel_op,             /* 0 */
-       &sysrq_loglevel_op,             /* 1 */
-       &sysrq_loglevel_op,             /* 2 */
-       &sysrq_loglevel_op,             /* 3 */
-       &sysrq_loglevel_op,             /* 4 */
-       &sysrq_loglevel_op,             /* 5 */
-       &sysrq_loglevel_op,             /* 6 */
-       &sysrq_loglevel_op,             /* 7 */
-       &sysrq_loglevel_op,             /* 8 */
-       &sysrq_loglevel_op,             /* 9 */
-
-       /*
-        * a: Don't use for system provided sysrqs, it is handled specially on
-        * sparc and will never arrive.
-        */
-       NULL,                           /* a */
-       &sysrq_reboot_op,               /* b */
-       &sysrq_crash_op,                /* c & ibm_emac driver debug */
-       &sysrq_showlocks_op,            /* d */
-       &sysrq_term_op,                 /* e */
-       &sysrq_moom_op,                 /* f */
-       /* g: May be registered for the kernel debugger */
-       NULL,                           /* g */
-       NULL,                           /* h - reserved for help */
-       &sysrq_kill_op,                 /* i */
-#ifdef CONFIG_BLOCK
-       &sysrq_thaw_op,                 /* j */
-#else
-       NULL,                           /* j */
-#endif
-       &sysrq_SAK_op,                  /* k */
-#ifdef CONFIG_SMP
-       &sysrq_showallcpus_op,          /* l */
-#else
-       NULL,                           /* l */
-#endif
-       &sysrq_showmem_op,              /* m */
-       &sysrq_unrt_op,                 /* n */
-       /* o: This will often be registered as 'Off' at init time */
-       NULL,                           /* o */
-       &sysrq_showregs_op,             /* p */
-       &sysrq_show_timers_op,          /* q */
-       &sysrq_unraw_op,                /* r */
-       &sysrq_sync_op,                 /* s */
-       &sysrq_showstate_op,            /* t */
-       &sysrq_mountro_op,              /* u */
-       /* v: May be registered for frame buffer console restore */
-       NULL,                           /* v */
-       &sysrq_showstate_blocked_op,    /* w */
-       /* x: May be registered on ppc/powerpc for xmon */
-       NULL,                           /* x */
-       /* y: May be registered on sparc64 for global register dump */
-       NULL,                           /* y */
-       &sysrq_ftrace_dump_op,          /* z */
-};
-
-/* key2index calculation, -1 on invalid index */
-static int sysrq_key_table_key2index(int key)
-{
-       int retval;
-
-       if ((key >= '0') && (key <= '9'))
-               retval = key - '0';
-       else if ((key >= 'a') && (key <= 'z'))
-               retval = key + 10 - 'a';
-       else
-               retval = -1;
-       return retval;
-}
-
-/*
- * get and put functions for the table, exposed to modules.
- */
-struct sysrq_key_op *__sysrq_get_key_op(int key)
-{
-        struct sysrq_key_op *op_p = NULL;
-        int i;
-
-       i = sysrq_key_table_key2index(key);
-       if (i != -1)
-               op_p = sysrq_key_table[i];
-
-        return op_p;
-}
-
-static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p)
-{
-        int i = sysrq_key_table_key2index(key);
-
-        if (i != -1)
-                sysrq_key_table[i] = op_p;
-}
-
-void __handle_sysrq(int key, bool check_mask)
-{
-       struct sysrq_key_op *op_p;
-       int orig_log_level;
-       int i;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sysrq_key_table_lock, flags);
-       /*
-        * Raise the apparent loglevel to maximum so that the sysrq header
-        * is shown to provide the user with positive feedback.  We do not
-        * simply emit this at KERN_EMERG as that would change message
-        * routing in the consumers of /proc/kmsg.
-        */
-       orig_log_level = console_loglevel;
-       console_loglevel = 7;
-       printk(KERN_INFO "SysRq : ");
-
-        op_p = __sysrq_get_key_op(key);
-        if (op_p) {
-               /*
-                * Should we check for enabled operations (/proc/sysrq-trigger
-                * should not) and is the invoked operation enabled?
-                */
-               if (!check_mask || sysrq_on_mask(op_p->enable_mask)) {
-                       printk("%s\n", op_p->action_msg);
-                       console_loglevel = orig_log_level;
-                       op_p->handler(key);
-               } else {
-                       printk("This sysrq operation is disabled.\n");
-               }
-       } else {
-               printk("HELP : ");
-               /* Only print the help msg once per handler */
-               for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) {
-                       if (sysrq_key_table[i]) {
-                               int j;
-
-                               for (j = 0; sysrq_key_table[i] !=
-                                               sysrq_key_table[j]; j++)
-                                       ;
-                               if (j != i)
-                                       continue;
-                               printk("%s ", sysrq_key_table[i]->help_msg);
-                       }
-               }
-               printk("\n");
-               console_loglevel = orig_log_level;
-       }
-       spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
-}
-
-void handle_sysrq(int key)
-{
-       if (sysrq_on())
-               __handle_sysrq(key, true);
-}
-EXPORT_SYMBOL(handle_sysrq);
-
-#ifdef CONFIG_INPUT
-
-/* Simple translation table for the SysRq keys */
-static const unsigned char sysrq_xlate[KEY_MAX + 1] =
-        "\000\0331234567890-=\177\t"                    /* 0x00 - 0x0f */
-        "qwertyuiop[]\r\000as"                          /* 0x10 - 0x1f */
-        "dfghjkl;'`\000\\zxcv"                          /* 0x20 - 0x2f */
-        "bnm,./\000*\000 \000\201\202\203\204\205"      /* 0x30 - 0x3f */
-        "\206\207\210\211\212\000\000789-456+1"         /* 0x40 - 0x4f */
-        "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
-        "\r\000/";                                      /* 0x60 - 0x6f */
-
-static bool sysrq_down;
-static int sysrq_alt_use;
-static int sysrq_alt;
-static DEFINE_SPINLOCK(sysrq_event_lock);
-
-static bool sysrq_filter(struct input_handle *handle, unsigned int type,
-                        unsigned int code, int value)
-{
-       bool suppress;
-
-       /* We are called with interrupts disabled, just take the lock */
-       spin_lock(&sysrq_event_lock);
-
-       if (type != EV_KEY)
-               goto out;
-
-       switch (code) {
-
-       case KEY_LEFTALT:
-       case KEY_RIGHTALT:
-               if (value)
-                       sysrq_alt = code;
-               else {
-                       if (sysrq_down && code == sysrq_alt_use)
-                               sysrq_down = false;
-
-                       sysrq_alt = 0;
-               }
-               break;
-
-       case KEY_SYSRQ:
-               if (value == 1 && sysrq_alt) {
-                       sysrq_down = true;
-                       sysrq_alt_use = sysrq_alt;
-               }
-               break;
-
-       default:
-               if (sysrq_down && value && value != 2)
-                       __handle_sysrq(sysrq_xlate[code], true);
-               break;
-       }
-
-out:
-       suppress = sysrq_down;
-       spin_unlock(&sysrq_event_lock);
-
-       return suppress;
-}
-
-static int sysrq_connect(struct input_handler *handler,
-                        struct input_dev *dev,
-                        const struct input_device_id *id)
-{
-       struct input_handle *handle;
-       int error;
-
-       sysrq_down = false;
-       sysrq_alt = 0;
-
-       handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
-       if (!handle)
-               return -ENOMEM;
-
-       handle->dev = dev;
-       handle->handler = handler;
-       handle->name = "sysrq";
-
-       error = input_register_handle(handle);
-       if (error) {
-               pr_err("Failed to register input sysrq handler, error %d\n",
-                       error);
-               goto err_free;
-       }
-
-       error = input_open_device(handle);
-       if (error) {
-               pr_err("Failed to open input device, error %d\n", error);
-               goto err_unregister;
-       }
-
-       return 0;
-
- err_unregister:
-       input_unregister_handle(handle);
- err_free:
-       kfree(handle);
-       return error;
-}
-
-static void sysrq_disconnect(struct input_handle *handle)
-{
-       input_close_device(handle);
-       input_unregister_handle(handle);
-       kfree(handle);
-}
-
-/*
- * We are matching on KEY_LEFTALT instead of KEY_SYSRQ because not all
- * keyboards have SysRq key predefined and so user may add it to keymap
- * later, but we expect all such keyboards to have left alt.
- */
-static const struct input_device_id sysrq_ids[] = {
-       {
-               .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
-                               INPUT_DEVICE_ID_MATCH_KEYBIT,
-               .evbit = { BIT_MASK(EV_KEY) },
-               .keybit = { BIT_MASK(KEY_LEFTALT) },
-       },
-       { },
-};
-
-static struct input_handler sysrq_handler = {
-       .filter         = sysrq_filter,
-       .connect        = sysrq_connect,
-       .disconnect     = sysrq_disconnect,
-       .name           = "sysrq",
-       .id_table       = sysrq_ids,
-};
-
-static bool sysrq_handler_registered;
-
-static inline void sysrq_register_handler(void)
-{
-       int error;
-
-       error = input_register_handler(&sysrq_handler);
-       if (error)
-               pr_err("Failed to register input handler, error %d", error);
-       else
-               sysrq_handler_registered = true;
-}
-
-static inline void sysrq_unregister_handler(void)
-{
-       if (sysrq_handler_registered) {
-               input_unregister_handler(&sysrq_handler);
-               sysrq_handler_registered = false;
-       }
-}
-
-#else
-
-static inline void sysrq_register_handler(void)
-{
-}
-
-static inline void sysrq_unregister_handler(void)
-{
-}
-
-#endif /* CONFIG_INPUT */
-
-int sysrq_toggle_support(int enable_mask)
-{
-       bool was_enabled = sysrq_on();
-
-       sysrq_enabled = enable_mask;
-
-       if (was_enabled != sysrq_on()) {
-               if (sysrq_on())
-                       sysrq_register_handler();
-               else
-                       sysrq_unregister_handler();
-       }
-
-       return 0;
-}
-
-static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
-                                struct sysrq_key_op *remove_op_p)
-{
-       int retval;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sysrq_key_table_lock, flags);
-       if (__sysrq_get_key_op(key) == remove_op_p) {
-               __sysrq_put_key_op(key, insert_op_p);
-               retval = 0;
-       } else {
-               retval = -1;
-       }
-       spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
-       return retval;
-}
-
-int register_sysrq_key(int key, struct sysrq_key_op *op_p)
-{
-       return __sysrq_swap_key_ops(key, op_p, NULL);
-}
-EXPORT_SYMBOL(register_sysrq_key);
-
-int unregister_sysrq_key(int key, struct sysrq_key_op *op_p)
-{
-       return __sysrq_swap_key_ops(key, NULL, op_p);
-}
-EXPORT_SYMBOL(unregister_sysrq_key);
-
-#ifdef CONFIG_PROC_FS
-/*
- * writing 'C' to /proc/sysrq-trigger is like sysrq-C
- */
-static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
-                                  size_t count, loff_t *ppos)
-{
-       if (count) {
-               char c;
-
-               if (get_user(c, buf))
-                       return -EFAULT;
-               __handle_sysrq(c, false);
-       }
-
-       return count;
-}
-
-static const struct file_operations proc_sysrq_trigger_operations = {
-       .write          = write_sysrq_trigger,
-       .llseek         = noop_llseek,
-};
-
-static void sysrq_init_procfs(void)
-{
-       if (!proc_create("sysrq-trigger", S_IWUSR, NULL,
-                        &proc_sysrq_trigger_operations))
-               pr_err("Failed to register proc interface\n");
-}
-
-#else
-
-static inline void sysrq_init_procfs(void)
-{
-}
-
-#endif /* CONFIG_PROC_FS */
-
-static int __init sysrq_init(void)
-{
-       sysrq_init_procfs();
-
-       if (sysrq_on())
-               sysrq_register_handler();
-
-       return 0;
-}
-module_init(sysrq_init);
diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c
deleted file mode 100644 (file)
index f64582b..0000000
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Creating audit events from TTY input.
- *
- * Copyright (C) 2007 Red Hat, Inc.  All rights reserved.  This copyrighted
- * material is made available to anyone wishing to use, modify, copy, or
- * redistribute it subject to the terms and conditions of the GNU General
- * Public License v.2.
- *
- * Authors: Miloslav Trmac <mitr@redhat.com>
- */
-
-#include <linux/audit.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-
-struct tty_audit_buf {
-       atomic_t count;
-       struct mutex mutex;     /* Protects all data below */
-       int major, minor;       /* The TTY which the data is from */
-       unsigned icanon:1;
-       size_t valid;
-       unsigned char *data;    /* Allocated size N_TTY_BUF_SIZE */
-};
-
-static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
-                                                int icanon)
-{
-       struct tty_audit_buf *buf;
-
-       buf = kmalloc(sizeof(*buf), GFP_KERNEL);
-       if (!buf)
-               goto err;
-       buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
-       if (!buf->data)
-               goto err_buf;
-       atomic_set(&buf->count, 1);
-       mutex_init(&buf->mutex);
-       buf->major = major;
-       buf->minor = minor;
-       buf->icanon = icanon;
-       buf->valid = 0;
-       return buf;
-
-err_buf:
-       kfree(buf);
-err:
-       return NULL;
-}
-
-static void tty_audit_buf_free(struct tty_audit_buf *buf)
-{
-       WARN_ON(buf->valid != 0);
-       kfree(buf->data);
-       kfree(buf);
-}
-
-static void tty_audit_buf_put(struct tty_audit_buf *buf)
-{
-       if (atomic_dec_and_test(&buf->count))
-               tty_audit_buf_free(buf);
-}
-
-static void tty_audit_log(const char *description, struct task_struct *tsk,
-                         uid_t loginuid, unsigned sessionid, int major,
-                         int minor, unsigned char *data, size_t size)
-{
-       struct audit_buffer *ab;
-
-       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY);
-       if (ab) {
-               char name[sizeof(tsk->comm)];
-               uid_t uid = task_uid(tsk);
-
-               audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u "
-                                "major=%d minor=%d comm=", description,
-                                tsk->pid, uid, loginuid, sessionid,
-                                major, minor);
-               get_task_comm(name, tsk);
-               audit_log_untrustedstring(ab, name);
-               audit_log_format(ab, " data=");
-               audit_log_n_hex(ab, data, size);
-               audit_log_end(ab);
-       }
-}
-
-/**
- *     tty_audit_buf_push      -       Push buffered data out
- *
- *     Generate an audit message from the contents of @buf, which is owned by
- *     @tsk with @loginuid.  @buf->mutex must be locked.
- */
-static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
-                              unsigned int sessionid,
-                              struct tty_audit_buf *buf)
-{
-       if (buf->valid == 0)
-               return;
-       if (audit_enabled == 0)
-               return;
-       tty_audit_log("tty", tsk, loginuid, sessionid, buf->major, buf->minor,
-                     buf->data, buf->valid);
-       buf->valid = 0;
-}
-
-/**
- *     tty_audit_buf_push_current      -       Push buffered data out
- *
- *     Generate an audit message from the contents of @buf, which is owned by
- *     the current task.  @buf->mutex must be locked.
- */
-static void tty_audit_buf_push_current(struct tty_audit_buf *buf)
-{
-       uid_t auid = audit_get_loginuid(current);
-       unsigned int sessionid = audit_get_sessionid(current);
-       tty_audit_buf_push(current, auid, sessionid, buf);
-}
-
-/**
- *     tty_audit_exit  -       Handle a task exit
- *
- *     Make sure all buffered data is written out and deallocate the buffer.
- *     Only needs to be called if current->signal->tty_audit_buf != %NULL.
- */
-void tty_audit_exit(void)
-{
-       struct tty_audit_buf *buf;
-
-       spin_lock_irq(&current->sighand->siglock);
-       buf = current->signal->tty_audit_buf;
-       current->signal->tty_audit_buf = NULL;
-       spin_unlock_irq(&current->sighand->siglock);
-       if (!buf)
-               return;
-
-       mutex_lock(&buf->mutex);
-       tty_audit_buf_push_current(buf);
-       mutex_unlock(&buf->mutex);
-
-       tty_audit_buf_put(buf);
-}
-
-/**
- *     tty_audit_fork  -       Copy TTY audit state for a new task
- *
- *     Set up TTY audit state in @sig from current.  @sig needs no locking.
- */
-void tty_audit_fork(struct signal_struct *sig)
-{
-       spin_lock_irq(&current->sighand->siglock);
-       sig->audit_tty = current->signal->audit_tty;
-       spin_unlock_irq(&current->sighand->siglock);
-}
-
-/**
- *     tty_audit_tiocsti       -       Log TIOCSTI
- */
-void tty_audit_tiocsti(struct tty_struct *tty, char ch)
-{
-       struct tty_audit_buf *buf;
-       int major, minor, should_audit;
-
-       spin_lock_irq(&current->sighand->siglock);
-       should_audit = current->signal->audit_tty;
-       buf = current->signal->tty_audit_buf;
-       if (buf)
-               atomic_inc(&buf->count);
-       spin_unlock_irq(&current->sighand->siglock);
-
-       major = tty->driver->major;
-       minor = tty->driver->minor_start + tty->index;
-       if (buf) {
-               mutex_lock(&buf->mutex);
-               if (buf->major == major && buf->minor == minor)
-                       tty_audit_buf_push_current(buf);
-               mutex_unlock(&buf->mutex);
-               tty_audit_buf_put(buf);
-       }
-
-       if (should_audit && audit_enabled) {
-               uid_t auid;
-               unsigned int sessionid;
-
-               auid = audit_get_loginuid(current);
-               sessionid = audit_get_sessionid(current);
-               tty_audit_log("ioctl=TIOCSTI", current, auid, sessionid, major,
-                             minor, &ch, 1);
-       }
-}
-
-/**
- * tty_audit_push_task -       Flush task's pending audit data
- * @tsk:               task pointer
- * @loginuid:          sender login uid
- * @sessionid:         sender session id
- *
- * Called with a ref on @tsk held. Try to lock sighand and get a
- * reference to the tty audit buffer if available.
- * Flush the buffer or return an appropriate error code.
- */
-int tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid)
-{
-       struct tty_audit_buf *buf = ERR_PTR(-EPERM);
-       unsigned long flags;
-
-       if (!lock_task_sighand(tsk, &flags))
-               return -ESRCH;
-
-       if (tsk->signal->audit_tty) {
-               buf = tsk->signal->tty_audit_buf;
-               if (buf)
-                       atomic_inc(&buf->count);
-       }
-       unlock_task_sighand(tsk, &flags);
-
-       /*
-        * Return 0 when signal->audit_tty set
-        * but tsk->signal->tty_audit_buf == NULL.
-        */
-       if (!buf || IS_ERR(buf))
-               return PTR_ERR(buf);
-
-       mutex_lock(&buf->mutex);
-       tty_audit_buf_push(tsk, loginuid, sessionid, buf);
-       mutex_unlock(&buf->mutex);
-
-       tty_audit_buf_put(buf);
-       return 0;
-}
-
-/**
- *     tty_audit_buf_get       -       Get an audit buffer.
- *
- *     Get an audit buffer for @tty, allocate it if necessary.  Return %NULL
- *     if TTY auditing is disabled or out of memory.  Otherwise, return a new
- *     reference to the buffer.
- */
-static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty)
-{
-       struct tty_audit_buf *buf, *buf2;
-
-       buf = NULL;
-       buf2 = NULL;
-       spin_lock_irq(&current->sighand->siglock);
-       if (likely(!current->signal->audit_tty))
-               goto out;
-       buf = current->signal->tty_audit_buf;
-       if (buf) {
-               atomic_inc(&buf->count);
-               goto out;
-       }
-       spin_unlock_irq(&current->sighand->siglock);
-
-       buf2 = tty_audit_buf_alloc(tty->driver->major,
-                                  tty->driver->minor_start + tty->index,
-                                  tty->icanon);
-       if (buf2 == NULL) {
-               audit_log_lost("out of memory in TTY auditing");
-               return NULL;
-       }
-
-       spin_lock_irq(&current->sighand->siglock);
-       if (!current->signal->audit_tty)
-               goto out;
-       buf = current->signal->tty_audit_buf;
-       if (!buf) {
-               current->signal->tty_audit_buf = buf2;
-               buf = buf2;
-               buf2 = NULL;
-       }
-       atomic_inc(&buf->count);
-       /* Fall through */
- out:
-       spin_unlock_irq(&current->sighand->siglock);
-       if (buf2)
-               tty_audit_buf_free(buf2);
-       return buf;
-}
-
-/**
- *     tty_audit_add_data      -       Add data for TTY auditing.
- *
- *     Audit @data of @size from @tty, if necessary.
- */
-void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
-                       size_t size)
-{
-       struct tty_audit_buf *buf;
-       int major, minor;
-
-       if (unlikely(size == 0))
-               return;
-
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY
-           && tty->driver->subtype == PTY_TYPE_MASTER)
-               return;
-
-       buf = tty_audit_buf_get(tty);
-       if (!buf)
-               return;
-
-       mutex_lock(&buf->mutex);
-       major = tty->driver->major;
-       minor = tty->driver->minor_start + tty->index;
-       if (buf->major != major || buf->minor != minor
-           || buf->icanon != tty->icanon) {
-               tty_audit_buf_push_current(buf);
-               buf->major = major;
-               buf->minor = minor;
-               buf->icanon = tty->icanon;
-       }
-       do {
-               size_t run;
-
-               run = N_TTY_BUF_SIZE - buf->valid;
-               if (run > size)
-                       run = size;
-               memcpy(buf->data + buf->valid, data, run);
-               buf->valid += run;
-               data += run;
-               size -= run;
-               if (buf->valid == N_TTY_BUF_SIZE)
-                       tty_audit_buf_push_current(buf);
-       } while (size != 0);
-       mutex_unlock(&buf->mutex);
-       tty_audit_buf_put(buf);
-}
-
-/**
- *     tty_audit_push  -       Push buffered data out
- *
- *     Make sure no audit data is pending for @tty on the current process.
- */
-void tty_audit_push(struct tty_struct *tty)
-{
-       struct tty_audit_buf *buf;
-
-       spin_lock_irq(&current->sighand->siglock);
-       if (likely(!current->signal->audit_tty)) {
-               spin_unlock_irq(&current->sighand->siglock);
-               return;
-       }
-       buf = current->signal->tty_audit_buf;
-       if (buf)
-               atomic_inc(&buf->count);
-       spin_unlock_irq(&current->sighand->siglock);
-
-       if (buf) {
-               int major, minor;
-
-               major = tty->driver->major;
-               minor = tty->driver->minor_start + tty->index;
-               mutex_lock(&buf->mutex);
-               if (buf->major == major && buf->minor == minor)
-                       tty_audit_buf_push_current(buf);
-               mutex_unlock(&buf->mutex);
-               tty_audit_buf_put(buf);
-       }
-}
diff --git a/drivers/char/tty_buffer.c b/drivers/char/tty_buffer.c
deleted file mode 100644 (file)
index cc1e985..0000000
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * Tty buffer allocation management
- */
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-
-/**
- *     tty_buffer_free_all             -       free buffers used by a tty
- *     @tty: tty to free from
- *
- *     Remove all the buffers pending on a tty whether queued with data
- *     or in the free ring. Must be called when the tty is no longer in use
- *
- *     Locking: none
- */
-
-void tty_buffer_free_all(struct tty_struct *tty)
-{
-       struct tty_buffer *thead;
-       while ((thead = tty->buf.head) != NULL) {
-               tty->buf.head = thead->next;
-               kfree(thead);
-       }
-       while ((thead = tty->buf.free) != NULL) {
-               tty->buf.free = thead->next;
-               kfree(thead);
-       }
-       tty->buf.tail = NULL;
-       tty->buf.memory_used = 0;
-}
-
-/**
- *     tty_buffer_alloc        -       allocate a tty buffer
- *     @tty: tty device
- *     @size: desired size (characters)
- *
- *     Allocate a new tty buffer to hold the desired number of characters.
- *     Return NULL if out of memory or the allocation would exceed the
- *     per device queue
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
-{
-       struct tty_buffer *p;
-
-       if (tty->buf.memory_used + size > 65536)
-               return NULL;
-       p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
-       if (p == NULL)
-               return NULL;
-       p->used = 0;
-       p->size = size;
-       p->next = NULL;
-       p->commit = 0;
-       p->read = 0;
-       p->char_buf_ptr = (char *)(p->data);
-       p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
-       tty->buf.memory_used += size;
-       return p;
-}
-
-/**
- *     tty_buffer_free         -       free a tty buffer
- *     @tty: tty owning the buffer
- *     @b: the buffer to free
- *
- *     Free a tty buffer, or add it to the free list according to our
- *     internal strategy
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
-{
-       /* Dumb strategy for now - should keep some stats */
-       tty->buf.memory_used -= b->size;
-       WARN_ON(tty->buf.memory_used < 0);
-
-       if (b->size >= 512)
-               kfree(b);
-       else {
-               b->next = tty->buf.free;
-               tty->buf.free = b;
-       }
-}
-
-/**
- *     __tty_buffer_flush              -       flush full tty buffers
- *     @tty: tty to flush
- *
- *     flush all the buffers containing receive data. Caller must
- *     hold the buffer lock and must have ensured no parallel flush to
- *     ldisc is running.
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static void __tty_buffer_flush(struct tty_struct *tty)
-{
-       struct tty_buffer *thead;
-
-       while ((thead = tty->buf.head) != NULL) {
-               tty->buf.head = thead->next;
-               tty_buffer_free(tty, thead);
-       }
-       tty->buf.tail = NULL;
-}
-
-/**
- *     tty_buffer_flush                -       flush full tty buffers
- *     @tty: tty to flush
- *
- *     flush all the buffers containing receive data. If the buffer is
- *     being processed by flush_to_ldisc then we defer the processing
- *     to that function
- *
- *     Locking: none
- */
-
-void tty_buffer_flush(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->buf.lock, flags);
-
-       /* If the data is being pushed to the tty layer then we can't
-          process it here. Instead set a flag and the flush_to_ldisc
-          path will process the flush request before it exits */
-       if (test_bit(TTY_FLUSHING, &tty->flags)) {
-               set_bit(TTY_FLUSHPENDING, &tty->flags);
-               spin_unlock_irqrestore(&tty->buf.lock, flags);
-               wait_event(tty->read_wait,
-                               test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
-               return;
-       } else
-               __tty_buffer_flush(tty);
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-}
-
-/**
- *     tty_buffer_find         -       find a free tty buffer
- *     @tty: tty owning the buffer
- *     @size: characters wanted
- *
- *     Locate an existing suitable tty buffer or if we are lacking one then
- *     allocate a new one. We round our buffers off in 256 character chunks
- *     to get better allocation behaviour.
- *
- *     Locking: Caller must hold tty->buf.lock
- */
-
-static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
-{
-       struct tty_buffer **tbh = &tty->buf.free;
-       while ((*tbh) != NULL) {
-               struct tty_buffer *t = *tbh;
-               if (t->size >= size) {
-                       *tbh = t->next;
-                       t->next = NULL;
-                       t->used = 0;
-                       t->commit = 0;
-                       t->read = 0;
-                       tty->buf.memory_used += t->size;
-                       return t;
-               }
-               tbh = &((*tbh)->next);
-       }
-       /* Round the buffer size out */
-       size = (size + 0xFF) & ~0xFF;
-       return tty_buffer_alloc(tty, size);
-       /* Should possibly check if this fails for the largest buffer we
-          have queued and recycle that ? */
-}
-
-/**
- *     tty_buffer_request_room         -       grow tty buffer if needed
- *     @tty: tty structure
- *     @size: size desired
- *
- *     Make at least size bytes of linear space available for the tty
- *     buffer. If we fail return the size we managed to find.
- *
- *     Locking: Takes tty->buf.lock
- */
-int tty_buffer_request_room(struct tty_struct *tty, size_t size)
-{
-       struct tty_buffer *b, *n;
-       int left;
-       unsigned long flags;
-
-       spin_lock_irqsave(&tty->buf.lock, flags);
-
-       /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
-          remove this conditional if its worth it. This would be invisible
-          to the callers */
-       if ((b = tty->buf.tail) != NULL)
-               left = b->size - b->used;
-       else
-               left = 0;
-
-       if (left < size) {
-               /* This is the slow path - looking for new buffers to use */
-               if ((n = tty_buffer_find(tty, size)) != NULL) {
-                       if (b != NULL) {
-                               b->next = n;
-                               b->commit = b->used;
-                       } else
-                               tty->buf.head = n;
-                       tty->buf.tail = n;
-               } else
-                       size = left;
-       }
-
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-       return size;
-}
-EXPORT_SYMBOL_GPL(tty_buffer_request_room);
-
-/**
- *     tty_insert_flip_string_fixed_flag - Add characters to the tty buffer
- *     @tty: tty structure
- *     @chars: characters
- *     @flag: flag value for each character
- *     @size: size
- *
- *     Queue a series of bytes to the tty buffering. All the characters
- *     passed are marked with the supplied flag. Returns the number added.
- *
- *     Locking: Called functions may take tty->buf.lock
- */
-
-int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
-               const unsigned char *chars, char flag, size_t size)
-{
-       int copied = 0;
-       do {
-               int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
-               int space = tty_buffer_request_room(tty, goal);
-               struct tty_buffer *tb = tty->buf.tail;
-               /* If there is no space then tb may be NULL */
-               if (unlikely(space == 0))
-                       break;
-               memcpy(tb->char_buf_ptr + tb->used, chars, space);
-               memset(tb->flag_buf_ptr + tb->used, flag, space);
-               tb->used += space;
-               copied += space;
-               chars += space;
-               /* There is a small chance that we need to split the data over
-                  several buffers. If this is the case we must loop */
-       } while (unlikely(size > copied));
-       return copied;
-}
-EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag);
-
-/**
- *     tty_insert_flip_string_flags    -       Add characters to the tty buffer
- *     @tty: tty structure
- *     @chars: characters
- *     @flags: flag bytes
- *     @size: size
- *
- *     Queue a series of bytes to the tty buffering. For each character
- *     the flags array indicates the status of the character. Returns the
- *     number added.
- *
- *     Locking: Called functions may take tty->buf.lock
- */
-
-int tty_insert_flip_string_flags(struct tty_struct *tty,
-               const unsigned char *chars, const char *flags, size_t size)
-{
-       int copied = 0;
-       do {
-               int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
-               int space = tty_buffer_request_room(tty, goal);
-               struct tty_buffer *tb = tty->buf.tail;
-               /* If there is no space then tb may be NULL */
-               if (unlikely(space == 0))
-                       break;
-               memcpy(tb->char_buf_ptr + tb->used, chars, space);
-               memcpy(tb->flag_buf_ptr + tb->used, flags, space);
-               tb->used += space;
-               copied += space;
-               chars += space;
-               flags += space;
-               /* There is a small chance that we need to split the data over
-                  several buffers. If this is the case we must loop */
-       } while (unlikely(size > copied));
-       return copied;
-}
-EXPORT_SYMBOL(tty_insert_flip_string_flags);
-
-/**
- *     tty_schedule_flip       -       push characters to ldisc
- *     @tty: tty to push from
- *
- *     Takes any pending buffers and transfers their ownership to the
- *     ldisc side of the queue. It then schedules those characters for
- *     processing by the line discipline.
- *
- *     Locking: Takes tty->buf.lock
- */
-
-void tty_schedule_flip(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->buf.lock, flags);
-       if (tty->buf.tail != NULL)
-               tty->buf.tail->commit = tty->buf.tail->used;
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-       schedule_delayed_work(&tty->buf.work, 1);
-}
-EXPORT_SYMBOL(tty_schedule_flip);
-
-/**
- *     tty_prepare_flip_string         -       make room for characters
- *     @tty: tty
- *     @chars: return pointer for character write area
- *     @size: desired size
- *
- *     Prepare a block of space in the buffer for data. Returns the length
- *     available and buffer pointer to the space which is now allocated and
- *     accounted for as ready for normal characters. This is used for drivers
- *     that need their own block copy routines into the buffer. There is no
- *     guarantee the buffer is a DMA target!
- *
- *     Locking: May call functions taking tty->buf.lock
- */
-
-int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
-                                                               size_t size)
-{
-       int space = tty_buffer_request_room(tty, size);
-       if (likely(space)) {
-               struct tty_buffer *tb = tty->buf.tail;
-               *chars = tb->char_buf_ptr + tb->used;
-               memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
-               tb->used += space;
-       }
-       return space;
-}
-EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
-
-/**
- *     tty_prepare_flip_string_flags   -       make room for characters
- *     @tty: tty
- *     @chars: return pointer for character write area
- *     @flags: return pointer for status flag write area
- *     @size: desired size
- *
- *     Prepare a block of space in the buffer for data. Returns the length
- *     available and buffer pointer to the space which is now allocated and
- *     accounted for as ready for characters. This is used for drivers
- *     that need their own block copy routines into the buffer. There is no
- *     guarantee the buffer is a DMA target!
- *
- *     Locking: May call functions taking tty->buf.lock
- */
-
-int tty_prepare_flip_string_flags(struct tty_struct *tty,
-                       unsigned char **chars, char **flags, size_t size)
-{
-       int space = tty_buffer_request_room(tty, size);
-       if (likely(space)) {
-               struct tty_buffer *tb = tty->buf.tail;
-               *chars = tb->char_buf_ptr + tb->used;
-               *flags = tb->flag_buf_ptr + tb->used;
-               tb->used += space;
-       }
-       return space;
-}
-EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
-
-
-
-/**
- *     flush_to_ldisc
- *     @work: tty structure passed from work queue.
- *
- *     This routine is called out of the software interrupt to flush data
- *     from the buffer chain to the line discipline.
- *
- *     Locking: holds tty->buf.lock to guard buffer list. Drops the lock
- *     while invoking the line discipline receive_buf method. The
- *     receive_buf method is single threaded for each tty instance.
- */
-
-static void flush_to_ldisc(struct work_struct *work)
-{
-       struct tty_struct *tty =
-               container_of(work, struct tty_struct, buf.work.work);
-       unsigned long   flags;
-       struct tty_ldisc *disc;
-
-       disc = tty_ldisc_ref(tty);
-       if (disc == NULL)       /*  !TTY_LDISC */
-               return;
-
-       spin_lock_irqsave(&tty->buf.lock, flags);
-
-       if (!test_and_set_bit(TTY_FLUSHING, &tty->flags)) {
-               struct tty_buffer *head;
-               while ((head = tty->buf.head) != NULL) {
-                       int count;
-                       char *char_buf;
-                       unsigned char *flag_buf;
-
-                       count = head->commit - head->read;
-                       if (!count) {
-                               if (head->next == NULL)
-                                       break;
-                               tty->buf.head = head->next;
-                               tty_buffer_free(tty, head);
-                               continue;
-                       }
-                       /* Ldisc or user is trying to flush the buffers
-                          we are feeding to the ldisc, stop feeding the
-                          line discipline as we want to empty the queue */
-                       if (test_bit(TTY_FLUSHPENDING, &tty->flags))
-                               break;
-                       if (!tty->receive_room) {
-                               schedule_delayed_work(&tty->buf.work, 1);
-                               break;
-                       }
-                       if (count > tty->receive_room)
-                               count = tty->receive_room;
-                       char_buf = head->char_buf_ptr + head->read;
-                       flag_buf = head->flag_buf_ptr + head->read;
-                       head->read += count;
-                       spin_unlock_irqrestore(&tty->buf.lock, flags);
-                       disc->ops->receive_buf(tty, char_buf,
-                                                       flag_buf, count);
-                       spin_lock_irqsave(&tty->buf.lock, flags);
-               }
-               clear_bit(TTY_FLUSHING, &tty->flags);
-       }
-
-       /* We may have a deferred request to flush the input buffer,
-          if so pull the chain under the lock and empty the queue */
-       if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
-               __tty_buffer_flush(tty);
-               clear_bit(TTY_FLUSHPENDING, &tty->flags);
-               wake_up(&tty->read_wait);
-       }
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-
-       tty_ldisc_deref(disc);
-}
-
-/**
- *     tty_flush_to_ldisc
- *     @tty: tty to push
- *
- *     Push the terminal flip buffers to the line discipline.
- *
- *     Must not be called from IRQ context.
- */
-void tty_flush_to_ldisc(struct tty_struct *tty)
-{
-       flush_delayed_work(&tty->buf.work);
-}
-
-/**
- *     tty_flip_buffer_push    -       terminal
- *     @tty: tty to push
- *
- *     Queue a push of the terminal flip buffers to the line discipline. This
- *     function must not be called from IRQ context if tty->low_latency is set.
- *
- *     In the event of the queue being busy for flipping the work will be
- *     held off and retried later.
- *
- *     Locking: tty buffer lock. Driver locks in low latency mode.
- */
-
-void tty_flip_buffer_push(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->buf.lock, flags);
-       if (tty->buf.tail != NULL)
-               tty->buf.tail->commit = tty->buf.tail->used;
-       spin_unlock_irqrestore(&tty->buf.lock, flags);
-
-       if (tty->low_latency)
-               flush_to_ldisc(&tty->buf.work.work);
-       else
-               schedule_delayed_work(&tty->buf.work, 1);
-}
-EXPORT_SYMBOL(tty_flip_buffer_push);
-
-/**
- *     tty_buffer_init         -       prepare a tty buffer structure
- *     @tty: tty to initialise
- *
- *     Set up the initial state of the buffer management for a tty device.
- *     Must be called before the other tty buffer functions are used.
- *
- *     Locking: none
- */
-
-void tty_buffer_init(struct tty_struct *tty)
-{
-       spin_lock_init(&tty->buf.lock);
-       tty->buf.head = NULL;
-       tty->buf.tail = NULL;
-       tty->buf.free = NULL;
-       tty->buf.memory_used = 0;
-       INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
-}
-
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
deleted file mode 100644 (file)
index c05c5af..0000000
+++ /dev/null
@@ -1,3263 +0,0 @@
-/*
- *  linux/drivers/char/tty_io.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-/*
- * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
- * or rs-channels. It also implements echoing, cooked mode etc.
- *
- * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
- *
- * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the
- * tty_struct and tty_queue structures.  Previously there was an array
- * of 256 tty_struct's which was statically allocated, and the
- * tty_queue structures were allocated at boot time.  Both are now
- * dynamically allocated only when the tty is open.
- *
- * Also restructured routines so that there is more of a separation
- * between the high-level tty routines (tty_io.c and tty_ioctl.c) and
- * the low-level tty routines (serial.c, pty.c, console.c).  This
- * makes for cleaner and more compact code.  -TYT, 9/17/92
- *
- * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
- * which can be dynamically activated and de-activated by the line
- * discipline handling modules (like SLIP).
- *
- * NOTE: pay no attention to the line discipline code (yet); its
- * interface is still subject to change in this version...
- * -- TYT, 1/31/92
- *
- * Added functionality to the OPOST tty handling.  No delays, but all
- * other bits should be there.
- *     -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
- *
- * Rewrote canonical mode and added more termios flags.
- *     -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
- *
- * Reorganized FASYNC support so mouse code can share it.
- *     -- ctm@ardi.com, 9Sep95
- *
- * New TIOCLINUX variants added.
- *     -- mj@k332.feld.cvut.cz, 19-Nov-95
- *
- * Restrict vt switching via ioctl()
- *      -- grif@cs.ucr.edu, 5-Dec-95
- *
- * Move console and virtual terminal code to more appropriate files,
- * implement CONFIG_VT and generalize console device interface.
- *     -- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97
- *
- * Rewrote tty_init_dev and tty_release_dev to eliminate races.
- *     -- Bill Hawes <whawes@star.net>, June 97
- *
- * Added devfs support.
- *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 13-Jan-1998
- *
- * Added support for a Unix98-style ptmx device.
- *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
- *
- * Reduced memory usage for older ARM systems
- *      -- Russell King <rmk@arm.linux.org.uk>
- *
- * Move do_SAK() into process context.  Less stack use in devfs functions.
- * alloc_tty_struct() always uses kmalloc()
- *                      -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01
- */
-
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/devpts_fs.h>
-#include <linux/file.h>
-#include <linux/fdtable.h>
-#include <linux/console.h>
-#include <linux/timer.h>
-#include <linux/ctype.h>
-#include <linux/kd.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/smp_lock.h>
-#include <linux/device.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/seq_file.h>
-#include <linux/serial.h>
-
-#include <linux/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-
-#include <linux/kmod.h>
-#include <linux/nsproxy.h>
-
-#undef TTY_DEBUG_HANGUP
-
-#define TTY_PARANOIA_CHECK 1
-#define CHECK_TTY_COUNT 1
-
-struct ktermios tty_std_termios = {    /* for the benefit of tty drivers  */
-       .c_iflag = ICRNL | IXON,
-       .c_oflag = OPOST | ONLCR,
-       .c_cflag = B38400 | CS8 | CREAD | HUPCL,
-       .c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
-                  ECHOCTL | ECHOKE | IEXTEN,
-       .c_cc = INIT_C_CC,
-       .c_ispeed = 38400,
-       .c_ospeed = 38400
-};
-
-EXPORT_SYMBOL(tty_std_termios);
-
-/* This list gets poked at by procfs and various bits of boot up code. This
-   could do with some rationalisation such as pulling the tty proc function
-   into this file */
-
-LIST_HEAD(tty_drivers);                        /* linked list of tty drivers */
-
-/* Mutex to protect creating and releasing a tty. This is shared with
-   vt.c for deeply disgusting hack reasons */
-DEFINE_MUTEX(tty_mutex);
-EXPORT_SYMBOL(tty_mutex);
-
-/* Spinlock to protect the tty->tty_files list */
-DEFINE_SPINLOCK(tty_files_lock);
-
-static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
-static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
-ssize_t redirected_tty_write(struct file *, const char __user *,
-                                                       size_t, loff_t *);
-static unsigned int tty_poll(struct file *, poll_table *);
-static int tty_open(struct inode *, struct file *);
-long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-#ifdef CONFIG_COMPAT
-static long tty_compat_ioctl(struct file *file, unsigned int cmd,
-                               unsigned long arg);
-#else
-#define tty_compat_ioctl NULL
-#endif
-static int __tty_fasync(int fd, struct file *filp, int on);
-static int tty_fasync(int fd, struct file *filp, int on);
-static void release_tty(struct tty_struct *tty, int idx);
-static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
-static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
-
-/**
- *     alloc_tty_struct        -       allocate a tty object
- *
- *     Return a new empty tty structure. The data fields have not
- *     been initialized in any way but has been zeroed
- *
- *     Locking: none
- */
-
-struct tty_struct *alloc_tty_struct(void)
-{
-       return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
-}
-
-/**
- *     free_tty_struct         -       free a disused tty
- *     @tty: tty struct to free
- *
- *     Free the write buffers, tty queue and tty memory itself.
- *
- *     Locking: none. Must be called after tty is definitely unused
- */
-
-void free_tty_struct(struct tty_struct *tty)
-{
-       if (tty->dev)
-               put_device(tty->dev);
-       kfree(tty->write_buf);
-       tty_buffer_free_all(tty);
-       kfree(tty);
-}
-
-static inline struct tty_struct *file_tty(struct file *file)
-{
-       return ((struct tty_file_private *)file->private_data)->tty;
-}
-
-/* Associate a new file with the tty structure */
-int tty_add_file(struct tty_struct *tty, struct file *file)
-{
-       struct tty_file_private *priv;
-
-       priv = kmalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->tty = tty;
-       priv->file = file;
-       file->private_data = priv;
-
-       spin_lock(&tty_files_lock);
-       list_add(&priv->list, &tty->tty_files);
-       spin_unlock(&tty_files_lock);
-
-       return 0;
-}
-
-/* Delete file from its tty */
-void tty_del_file(struct file *file)
-{
-       struct tty_file_private *priv = file->private_data;
-
-       spin_lock(&tty_files_lock);
-       list_del(&priv->list);
-       spin_unlock(&tty_files_lock);
-       file->private_data = NULL;
-       kfree(priv);
-}
-
-
-#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base)
-
-/**
- *     tty_name        -       return tty naming
- *     @tty: tty structure
- *     @buf: buffer for output
- *
- *     Convert a tty structure into a name. The name reflects the kernel
- *     naming policy and if udev is in use may not reflect user space
- *
- *     Locking: none
- */
-
-char *tty_name(struct tty_struct *tty, char *buf)
-{
-       if (!tty) /* Hmm.  NULL pointer.  That's fun. */
-               strcpy(buf, "NULL tty");
-       else
-               strcpy(buf, tty->name);
-       return buf;
-}
-
-EXPORT_SYMBOL(tty_name);
-
-int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
-                             const char *routine)
-{
-#ifdef TTY_PARANOIA_CHECK
-       if (!tty) {
-               printk(KERN_WARNING
-                       "null TTY for (%d:%d) in %s\n",
-                       imajor(inode), iminor(inode), routine);
-               return 1;
-       }
-       if (tty->magic != TTY_MAGIC) {
-               printk(KERN_WARNING
-                       "bad magic number for tty struct (%d:%d) in %s\n",
-                       imajor(inode), iminor(inode), routine);
-               return 1;
-       }
-#endif
-       return 0;
-}
-
-static int check_tty_count(struct tty_struct *tty, const char *routine)
-{
-#ifdef CHECK_TTY_COUNT
-       struct list_head *p;
-       int count = 0;
-
-       spin_lock(&tty_files_lock);
-       list_for_each(p, &tty->tty_files) {
-               count++;
-       }
-       spin_unlock(&tty_files_lock);
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-           tty->driver->subtype == PTY_TYPE_SLAVE &&
-           tty->link && tty->link->count)
-               count++;
-       if (tty->count != count) {
-               printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) "
-                                   "!= #fd's(%d) in %s\n",
-                      tty->name, tty->count, count, routine);
-               return count;
-       }
-#endif
-       return 0;
-}
-
-/**
- *     get_tty_driver          -       find device of a tty
- *     @dev_t: device identifier
- *     @index: returns the index of the tty
- *
- *     This routine returns a tty driver structure, given a device number
- *     and also passes back the index number.
- *
- *     Locking: caller must hold tty_mutex
- */
-
-static struct tty_driver *get_tty_driver(dev_t device, int *index)
-{
-       struct tty_driver *p;
-
-       list_for_each_entry(p, &tty_drivers, tty_drivers) {
-               dev_t base = MKDEV(p->major, p->minor_start);
-               if (device < base || device >= base + p->num)
-                       continue;
-               *index = device - base;
-               return tty_driver_kref_get(p);
-       }
-       return NULL;
-}
-
-#ifdef CONFIG_CONSOLE_POLL
-
-/**
- *     tty_find_polling_driver -       find device of a polled tty
- *     @name: name string to match
- *     @line: pointer to resulting tty line nr
- *
- *     This routine returns a tty driver structure, given a name
- *     and the condition that the tty driver is capable of polled
- *     operation.
- */
-struct tty_driver *tty_find_polling_driver(char *name, int *line)
-{
-       struct tty_driver *p, *res = NULL;
-       int tty_line = 0;
-       int len;
-       char *str, *stp;
-
-       for (str = name; *str; str++)
-               if ((*str >= '0' && *str <= '9') || *str == ',')
-                       break;
-       if (!*str)
-               return NULL;
-
-       len = str - name;
-       tty_line = simple_strtoul(str, &str, 10);
-
-       mutex_lock(&tty_mutex);
-       /* Search through the tty devices to look for a match */
-       list_for_each_entry(p, &tty_drivers, tty_drivers) {
-               if (strncmp(name, p->name, len) != 0)
-                       continue;
-               stp = str;
-               if (*stp == ',')
-                       stp++;
-               if (*stp == '\0')
-                       stp = NULL;
-
-               if (tty_line >= 0 && tty_line < p->num && p->ops &&
-                   p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) {
-                       res = tty_driver_kref_get(p);
-                       *line = tty_line;
-                       break;
-               }
-       }
-       mutex_unlock(&tty_mutex);
-
-       return res;
-}
-EXPORT_SYMBOL_GPL(tty_find_polling_driver);
-#endif
-
-/**
- *     tty_check_change        -       check for POSIX terminal changes
- *     @tty: tty to check
- *
- *     If we try to write to, or set the state of, a terminal and we're
- *     not in the foreground, send a SIGTTOU.  If the signal is blocked or
- *     ignored, go ahead and perform the operation.  (POSIX 7.2)
- *
- *     Locking: ctrl_lock
- */
-
-int tty_check_change(struct tty_struct *tty)
-{
-       unsigned long flags;
-       int ret = 0;
-
-       if (current->signal->tty != tty)
-               return 0;
-
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-
-       if (!tty->pgrp) {
-               printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n");
-               goto out_unlock;
-       }
-       if (task_pgrp(current) == tty->pgrp)
-               goto out_unlock;
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-       if (is_ignored(SIGTTOU))
-               goto out;
-       if (is_current_pgrp_orphaned()) {
-               ret = -EIO;
-               goto out;
-       }
-       kill_pgrp(task_pgrp(current), SIGTTOU, 1);
-       set_thread_flag(TIF_SIGPENDING);
-       ret = -ERESTARTSYS;
-out:
-       return ret;
-out_unlock:
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-       return ret;
-}
-
-EXPORT_SYMBOL(tty_check_change);
-
-static ssize_t hung_up_tty_read(struct file *file, char __user *buf,
-                               size_t count, loff_t *ppos)
-{
-       return 0;
-}
-
-static ssize_t hung_up_tty_write(struct file *file, const char __user *buf,
-                                size_t count, loff_t *ppos)
-{
-       return -EIO;
-}
-
-/* No kernel lock held - none needed ;) */
-static unsigned int hung_up_tty_poll(struct file *filp, poll_table *wait)
-{
-       return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
-}
-
-static long hung_up_tty_ioctl(struct file *file, unsigned int cmd,
-               unsigned long arg)
-{
-       return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
-}
-
-static long hung_up_tty_compat_ioctl(struct file *file,
-                                    unsigned int cmd, unsigned long arg)
-{
-       return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
-}
-
-static const struct file_operations tty_fops = {
-       .llseek         = no_llseek,
-       .read           = tty_read,
-       .write          = tty_write,
-       .poll           = tty_poll,
-       .unlocked_ioctl = tty_ioctl,
-       .compat_ioctl   = tty_compat_ioctl,
-       .open           = tty_open,
-       .release        = tty_release,
-       .fasync         = tty_fasync,
-};
-
-static const struct file_operations console_fops = {
-       .llseek         = no_llseek,
-       .read           = tty_read,
-       .write          = redirected_tty_write,
-       .poll           = tty_poll,
-       .unlocked_ioctl = tty_ioctl,
-       .compat_ioctl   = tty_compat_ioctl,
-       .open           = tty_open,
-       .release        = tty_release,
-       .fasync         = tty_fasync,
-};
-
-static const struct file_operations hung_up_tty_fops = {
-       .llseek         = no_llseek,
-       .read           = hung_up_tty_read,
-       .write          = hung_up_tty_write,
-       .poll           = hung_up_tty_poll,
-       .unlocked_ioctl = hung_up_tty_ioctl,
-       .compat_ioctl   = hung_up_tty_compat_ioctl,
-       .release        = tty_release,
-};
-
-static DEFINE_SPINLOCK(redirect_lock);
-static struct file *redirect;
-
-/**
- *     tty_wakeup      -       request more data
- *     @tty: terminal
- *
- *     Internal and external helper for wakeups of tty. This function
- *     informs the line discipline if present that the driver is ready
- *     to receive more output data.
- */
-
-void tty_wakeup(struct tty_struct *tty)
-{
-       struct tty_ldisc *ld;
-
-       if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) {
-               ld = tty_ldisc_ref(tty);
-               if (ld) {
-                       if (ld->ops->write_wakeup)
-                               ld->ops->write_wakeup(tty);
-                       tty_ldisc_deref(ld);
-               }
-       }
-       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
-}
-
-EXPORT_SYMBOL_GPL(tty_wakeup);
-
-/**
- *     __tty_hangup            -       actual handler for hangup events
- *     @work: tty device
- *
- *     This can be called by the "eventd" kernel thread.  That is process
- *     synchronous but doesn't hold any locks, so we need to make sure we
- *     have the appropriate locks for what we're doing.
- *
- *     The hangup event clears any pending redirections onto the hung up
- *     device. It ensures future writes will error and it does the needed
- *     line discipline hangup and signal delivery. The tty object itself
- *     remains intact.
- *
- *     Locking:
- *             BTM
- *               redirect lock for undoing redirection
- *               file list lock for manipulating list of ttys
- *               tty_ldisc_lock from called functions
- *               termios_mutex resetting termios data
- *               tasklist_lock to walk task list for hangup event
- *                 ->siglock to protect ->signal/->sighand
- */
-void __tty_hangup(struct tty_struct *tty)
-{
-       struct file *cons_filp = NULL;
-       struct file *filp, *f = NULL;
-       struct task_struct *p;
-       struct tty_file_private *priv;
-       int    closecount = 0, n;
-       unsigned long flags;
-       int refs = 0;
-
-       if (!tty)
-               return;
-
-
-       spin_lock(&redirect_lock);
-       if (redirect && file_tty(redirect) == tty) {
-               f = redirect;
-               redirect = NULL;
-       }
-       spin_unlock(&redirect_lock);
-
-       tty_lock();
-
-       /* inuse_filps is protected by the single tty lock,
-          this really needs to change if we want to flush the
-          workqueue with the lock held */
-       check_tty_count(tty, "tty_hangup");
-
-       spin_lock(&tty_files_lock);
-       /* This breaks for file handles being sent over AF_UNIX sockets ? */
-       list_for_each_entry(priv, &tty->tty_files, list) {
-               filp = priv->file;
-               if (filp->f_op->write == redirected_tty_write)
-                       cons_filp = filp;
-               if (filp->f_op->write != tty_write)
-                       continue;
-               closecount++;
-               __tty_fasync(-1, filp, 0);      /* can't block */
-               filp->f_op = &hung_up_tty_fops;
-       }
-       spin_unlock(&tty_files_lock);
-
-       tty_ldisc_hangup(tty);
-
-       read_lock(&tasklist_lock);
-       if (tty->session) {
-               do_each_pid_task(tty->session, PIDTYPE_SID, p) {
-                       spin_lock_irq(&p->sighand->siglock);
-                       if (p->signal->tty == tty) {
-                               p->signal->tty = NULL;
-                               /* We defer the dereferences outside fo
-                                  the tasklist lock */
-                               refs++;
-                       }
-                       if (!p->signal->leader) {
-                               spin_unlock_irq(&p->sighand->siglock);
-                               continue;
-                       }
-                       __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
-                       __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
-                       put_pid(p->signal->tty_old_pgrp);  /* A noop */
-                       spin_lock_irqsave(&tty->ctrl_lock, flags);
-                       if (tty->pgrp)
-                               p->signal->tty_old_pgrp = get_pid(tty->pgrp);
-                       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-                       spin_unlock_irq(&p->sighand->siglock);
-               } while_each_pid_task(tty->session, PIDTYPE_SID, p);
-       }
-       read_unlock(&tasklist_lock);
-
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       clear_bit(TTY_THROTTLED, &tty->flags);
-       clear_bit(TTY_PUSH, &tty->flags);
-       clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
-       put_pid(tty->session);
-       put_pid(tty->pgrp);
-       tty->session = NULL;
-       tty->pgrp = NULL;
-       tty->ctrl_status = 0;
-       set_bit(TTY_HUPPED, &tty->flags);
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
-       /* Account for the p->signal references we killed */
-       while (refs--)
-               tty_kref_put(tty);
-
-       /*
-        * If one of the devices matches a console pointer, we
-        * cannot just call hangup() because that will cause
-        * tty->count and state->count to go out of sync.
-        * So we just call close() the right number of times.
-        */
-       if (cons_filp) {
-               if (tty->ops->close)
-                       for (n = 0; n < closecount; n++)
-                               tty->ops->close(tty, cons_filp);
-       } else if (tty->ops->hangup)
-               (tty->ops->hangup)(tty);
-       /*
-        * We don't want to have driver/ldisc interactions beyond
-        * the ones we did here. The driver layer expects no
-        * calls after ->hangup() from the ldisc side. However we
-        * can't yet guarantee all that.
-        */
-       set_bit(TTY_HUPPED, &tty->flags);
-       tty_ldisc_enable(tty);
-
-       tty_unlock();
-
-       if (f)
-               fput(f);
-}
-
-static void do_tty_hangup(struct work_struct *work)
-{
-       struct tty_struct *tty =
-               container_of(work, struct tty_struct, hangup_work);
-
-       __tty_hangup(tty);
-}
-
-/**
- *     tty_hangup              -       trigger a hangup event
- *     @tty: tty to hangup
- *
- *     A carrier loss (virtual or otherwise) has occurred on this like
- *     schedule a hangup sequence to run after this event.
- */
-
-void tty_hangup(struct tty_struct *tty)
-{
-#ifdef TTY_DEBUG_HANGUP
-       char    buf[64];
-       printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf));
-#endif
-       schedule_work(&tty->hangup_work);
-}
-
-EXPORT_SYMBOL(tty_hangup);
-
-/**
- *     tty_vhangup             -       process vhangup
- *     @tty: tty to hangup
- *
- *     The user has asked via system call for the terminal to be hung up.
- *     We do this synchronously so that when the syscall returns the process
- *     is complete. That guarantee is necessary for security reasons.
- */
-
-void tty_vhangup(struct tty_struct *tty)
-{
-#ifdef TTY_DEBUG_HANGUP
-       char    buf[64];
-
-       printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
-#endif
-       __tty_hangup(tty);
-}
-
-EXPORT_SYMBOL(tty_vhangup);
-
-
-/**
- *     tty_vhangup_self        -       process vhangup for own ctty
- *
- *     Perform a vhangup on the current controlling tty
- */
-
-void tty_vhangup_self(void)
-{
-       struct tty_struct *tty;
-
-       tty = get_current_tty();
-       if (tty) {
-               tty_vhangup(tty);
-               tty_kref_put(tty);
-       }
-}
-
-/**
- *     tty_hung_up_p           -       was tty hung up
- *     @filp: file pointer of tty
- *
- *     Return true if the tty has been subject to a vhangup or a carrier
- *     loss
- */
-
-int tty_hung_up_p(struct file *filp)
-{
-       return (filp->f_op == &hung_up_tty_fops);
-}
-
-EXPORT_SYMBOL(tty_hung_up_p);
-
-static void session_clear_tty(struct pid *session)
-{
-       struct task_struct *p;
-       do_each_pid_task(session, PIDTYPE_SID, p) {
-               proc_clear_tty(p);
-       } while_each_pid_task(session, PIDTYPE_SID, p);
-}
-
-/**
- *     disassociate_ctty       -       disconnect controlling tty
- *     @on_exit: true if exiting so need to "hang up" the session
- *
- *     This function is typically called only by the session leader, when
- *     it wants to disassociate itself from its controlling tty.
- *
- *     It performs the following functions:
- *     (1)  Sends a SIGHUP and SIGCONT to the foreground process group
- *     (2)  Clears the tty from being controlling the session
- *     (3)  Clears the controlling tty for all processes in the
- *             session group.
- *
- *     The argument on_exit is set to 1 if called when a process is
- *     exiting; it is 0 if called by the ioctl TIOCNOTTY.
- *
- *     Locking:
- *             BTM is taken for hysterical raisins, and held when
- *               called from no_tty().
- *               tty_mutex is taken to protect tty
- *               ->siglock is taken to protect ->signal/->sighand
- *               tasklist_lock is taken to walk process list for sessions
- *                 ->siglock is taken to protect ->signal/->sighand
- */
-
-void disassociate_ctty(int on_exit)
-{
-       struct tty_struct *tty;
-       struct pid *tty_pgrp = NULL;
-
-       if (!current->signal->leader)
-               return;
-
-       tty = get_current_tty();
-       if (tty) {
-               tty_pgrp = get_pid(tty->pgrp);
-               if (on_exit) {
-                       if (tty->driver->type != TTY_DRIVER_TYPE_PTY)
-                               tty_vhangup(tty);
-               }
-               tty_kref_put(tty);
-       } else if (on_exit) {
-               struct pid *old_pgrp;
-               spin_lock_irq(&current->sighand->siglock);
-               old_pgrp = current->signal->tty_old_pgrp;
-               current->signal->tty_old_pgrp = NULL;
-               spin_unlock_irq(&current->sighand->siglock);
-               if (old_pgrp) {
-                       kill_pgrp(old_pgrp, SIGHUP, on_exit);
-                       kill_pgrp(old_pgrp, SIGCONT, on_exit);
-                       put_pid(old_pgrp);
-               }
-               return;
-       }
-       if (tty_pgrp) {
-               kill_pgrp(tty_pgrp, SIGHUP, on_exit);
-               if (!on_exit)
-                       kill_pgrp(tty_pgrp, SIGCONT, on_exit);
-               put_pid(tty_pgrp);
-       }
-
-       spin_lock_irq(&current->sighand->siglock);
-       put_pid(current->signal->tty_old_pgrp);
-       current->signal->tty_old_pgrp = NULL;
-       spin_unlock_irq(&current->sighand->siglock);
-
-       tty = get_current_tty();
-       if (tty) {
-               unsigned long flags;
-               spin_lock_irqsave(&tty->ctrl_lock, flags);
-               put_pid(tty->session);
-               put_pid(tty->pgrp);
-               tty->session = NULL;
-               tty->pgrp = NULL;
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               tty_kref_put(tty);
-       } else {
-#ifdef TTY_DEBUG_HANGUP
-               printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
-                      " = NULL", tty);
-#endif
-       }
-
-       /* Now clear signal->tty under the lock */
-       read_lock(&tasklist_lock);
-       session_clear_tty(task_session(current));
-       read_unlock(&tasklist_lock);
-}
-
-/**
- *
- *     no_tty  - Ensure the current process does not have a controlling tty
- */
-void no_tty(void)
-{
-       struct task_struct *tsk = current;
-       tty_lock();
-       disassociate_ctty(0);
-       tty_unlock();
-       proc_clear_tty(tsk);
-}
-
-
-/**
- *     stop_tty        -       propagate flow control
- *     @tty: tty to stop
- *
- *     Perform flow control to the driver. For PTY/TTY pairs we
- *     must also propagate the TIOCKPKT status. May be called
- *     on an already stopped device and will not re-call the driver
- *     method.
- *
- *     This functionality is used by both the line disciplines for
- *     halting incoming flow and by the driver. It may therefore be
- *     called from any context, may be under the tty atomic_write_lock
- *     but not always.
- *
- *     Locking:
- *             Uses the tty control lock internally
- */
-
-void stop_tty(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       if (tty->stopped) {
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               return;
-       }
-       tty->stopped = 1;
-       if (tty->link && tty->link->packet) {
-               tty->ctrl_status &= ~TIOCPKT_START;
-               tty->ctrl_status |= TIOCPKT_STOP;
-               wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
-       }
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-       if (tty->ops->stop)
-               (tty->ops->stop)(tty);
-}
-
-EXPORT_SYMBOL(stop_tty);
-
-/**
- *     start_tty       -       propagate flow control
- *     @tty: tty to start
- *
- *     Start a tty that has been stopped if at all possible. Perform
- *     any necessary wakeups and propagate the TIOCPKT status. If this
- *     is the tty was previous stopped and is being started then the
- *     driver start method is invoked and the line discipline woken.
- *
- *     Locking:
- *             ctrl_lock
- */
-
-void start_tty(struct tty_struct *tty)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       if (!tty->stopped || tty->flow_stopped) {
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               return;
-       }
-       tty->stopped = 0;
-       if (tty->link && tty->link->packet) {
-               tty->ctrl_status &= ~TIOCPKT_STOP;
-               tty->ctrl_status |= TIOCPKT_START;
-               wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
-       }
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-       if (tty->ops->start)
-               (tty->ops->start)(tty);
-       /* If we have a running line discipline it may need kicking */
-       tty_wakeup(tty);
-}
-
-EXPORT_SYMBOL(start_tty);
-
-/**
- *     tty_read        -       read method for tty device files
- *     @file: pointer to tty file
- *     @buf: user buffer
- *     @count: size of user buffer
- *     @ppos: unused
- *
- *     Perform the read system call function on this terminal device. Checks
- *     for hung up devices before calling the line discipline method.
- *
- *     Locking:
- *             Locks the line discipline internally while needed. Multiple
- *     read calls may be outstanding in parallel.
- */
-
-static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
-                       loff_t *ppos)
-{
-       int i;
-       struct inode *inode = file->f_path.dentry->d_inode;
-       struct tty_struct *tty = file_tty(file);
-       struct tty_ldisc *ld;
-
-       if (tty_paranoia_check(tty, inode, "tty_read"))
-               return -EIO;
-       if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
-               return -EIO;
-
-       /* We want to wait for the line discipline to sort out in this
-          situation */
-       ld = tty_ldisc_ref_wait(tty);
-       if (ld->ops->read)
-               i = (ld->ops->read)(tty, file, buf, count);
-       else
-               i = -EIO;
-       tty_ldisc_deref(ld);
-       if (i > 0)
-               inode->i_atime = current_fs_time(inode->i_sb);
-       return i;
-}
-
-void tty_write_unlock(struct tty_struct *tty)
-{
-       mutex_unlock(&tty->atomic_write_lock);
-       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
-}
-
-int tty_write_lock(struct tty_struct *tty, int ndelay)
-{
-       if (!mutex_trylock(&tty->atomic_write_lock)) {
-               if (ndelay)
-                       return -EAGAIN;
-               if (mutex_lock_interruptible(&tty->atomic_write_lock))
-                       return -ERESTARTSYS;
-       }
-       return 0;
-}
-
-/*
- * Split writes up in sane blocksizes to avoid
- * denial-of-service type attacks
- */
-static inline ssize_t do_tty_write(
-       ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),
-       struct tty_struct *tty,
-       struct file *file,
-       const char __user *buf,
-       size_t count)
-{
-       ssize_t ret, written = 0;
-       unsigned int chunk;
-
-       ret = tty_write_lock(tty, file->f_flags & O_NDELAY);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * We chunk up writes into a temporary buffer. This
-        * simplifies low-level drivers immensely, since they
-        * don't have locking issues and user mode accesses.
-        *
-        * But if TTY_NO_WRITE_SPLIT is set, we should use a
-        * big chunk-size..
-        *
-        * The default chunk-size is 2kB, because the NTTY
-        * layer has problems with bigger chunks. It will
-        * claim to be able to handle more characters than
-        * it actually does.
-        *
-        * FIXME: This can probably go away now except that 64K chunks
-        * are too likely to fail unless switched to vmalloc...
-        */
-       chunk = 2048;
-       if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags))
-               chunk = 65536;
-       if (count < chunk)
-               chunk = count;
-
-       /* write_buf/write_cnt is protected by the atomic_write_lock mutex */
-       if (tty->write_cnt < chunk) {
-               unsigned char *buf_chunk;
-
-               if (chunk < 1024)
-                       chunk = 1024;
-
-               buf_chunk = kmalloc(chunk, GFP_KERNEL);
-               if (!buf_chunk) {
-                       ret = -ENOMEM;
-                       goto out;
-               }
-               kfree(tty->write_buf);
-               tty->write_cnt = chunk;
-               tty->write_buf = buf_chunk;
-       }
-
-       /* Do the write .. */
-       for (;;) {
-               size_t size = count;
-               if (size > chunk)
-                       size = chunk;
-               ret = -EFAULT;
-               if (copy_from_user(tty->write_buf, buf, size))
-                       break;
-               ret = write(tty, file, tty->write_buf, size);
-               if (ret <= 0)
-                       break;
-               written += ret;
-               buf += ret;
-               count -= ret;
-               if (!count)
-                       break;
-               ret = -ERESTARTSYS;
-               if (signal_pending(current))
-                       break;
-               cond_resched();
-       }
-       if (written) {
-               struct inode *inode = file->f_path.dentry->d_inode;
-               inode->i_mtime = current_fs_time(inode->i_sb);
-               ret = written;
-       }
-out:
-       tty_write_unlock(tty);
-       return ret;
-}
-
-/**
- * tty_write_message - write a message to a certain tty, not just the console.
- * @tty: the destination tty_struct
- * @msg: the message to write
- *
- * This is used for messages that need to be redirected to a specific tty.
- * We don't put it into the syslog queue right now maybe in the future if
- * really needed.
- *
- * We must still hold the BTM and test the CLOSING flag for the moment.
- */
-
-void tty_write_message(struct tty_struct *tty, char *msg)
-{
-       if (tty) {
-               mutex_lock(&tty->atomic_write_lock);
-               tty_lock();
-               if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
-                       tty_unlock();
-                       tty->ops->write(tty, msg, strlen(msg));
-               } else
-                       tty_unlock();
-               tty_write_unlock(tty);
-       }
-       return;
-}
-
-
-/**
- *     tty_write               -       write method for tty device file
- *     @file: tty file pointer
- *     @buf: user data to write
- *     @count: bytes to write
- *     @ppos: unused
- *
- *     Write data to a tty device via the line discipline.
- *
- *     Locking:
- *             Locks the line discipline as required
- *             Writes to the tty driver are serialized by the atomic_write_lock
- *     and are then processed in chunks to the device. The line discipline
- *     write method will not be invoked in parallel for each device.
- */
-
-static ssize_t tty_write(struct file *file, const char __user *buf,
-                                               size_t count, loff_t *ppos)
-{
-       struct inode *inode = file->f_path.dentry->d_inode;
-       struct tty_struct *tty = file_tty(file);
-       struct tty_ldisc *ld;
-       ssize_t ret;
-
-       if (tty_paranoia_check(tty, inode, "tty_write"))
-               return -EIO;
-       if (!tty || !tty->ops->write ||
-               (test_bit(TTY_IO_ERROR, &tty->flags)))
-                       return -EIO;
-       /* Short term debug to catch buggy drivers */
-       if (tty->ops->write_room == NULL)
-               printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
-                       tty->driver->name);
-       ld = tty_ldisc_ref_wait(tty);
-       if (!ld->ops->write)
-               ret = -EIO;
-       else
-               ret = do_tty_write(ld->ops->write, tty, file, buf, count);
-       tty_ldisc_deref(ld);
-       return ret;
-}
-
-ssize_t redirected_tty_write(struct file *file, const char __user *buf,
-                                               size_t count, loff_t *ppos)
-{
-       struct file *p = NULL;
-
-       spin_lock(&redirect_lock);
-       if (redirect) {
-               get_file(redirect);
-               p = redirect;
-       }
-       spin_unlock(&redirect_lock);
-
-       if (p) {
-               ssize_t res;
-               res = vfs_write(p, buf, count, &p->f_pos);
-               fput(p);
-               return res;
-       }
-       return tty_write(file, buf, count, ppos);
-}
-
-static char ptychar[] = "pqrstuvwxyzabcde";
-
-/**
- *     pty_line_name   -       generate name for a pty
- *     @driver: the tty driver in use
- *     @index: the minor number
- *     @p: output buffer of at least 6 bytes
- *
- *     Generate a name from a driver reference and write it to the output
- *     buffer.
- *
- *     Locking: None
- */
-static void pty_line_name(struct tty_driver *driver, int index, char *p)
-{
-       int i = index + driver->name_base;
-       /* ->name is initialized to "ttyp", but "tty" is expected */
-       sprintf(p, "%s%c%x",
-               driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name,
-               ptychar[i >> 4 & 0xf], i & 0xf);
-}
-
-/**
- *     tty_line_name   -       generate name for a tty
- *     @driver: the tty driver in use
- *     @index: the minor number
- *     @p: output buffer of at least 7 bytes
- *
- *     Generate a name from a driver reference and write it to the output
- *     buffer.
- *
- *     Locking: None
- */
-static void tty_line_name(struct tty_driver *driver, int index, char *p)
-{
-       sprintf(p, "%s%d", driver->name, index + driver->name_base);
-}
-
-/**
- *     tty_driver_lookup_tty() - find an existing tty, if any
- *     @driver: the driver for the tty
- *     @idx:    the minor number
- *
- *     Return the tty, if found or ERR_PTR() otherwise.
- *
- *     Locking: tty_mutex must be held. If tty is found, the mutex must
- *     be held until the 'fast-open' is also done. Will change once we
- *     have refcounting in the driver and per driver locking
- */
-static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
-               struct inode *inode, int idx)
-{
-       struct tty_struct *tty;
-
-       if (driver->ops->lookup)
-               return driver->ops->lookup(driver, inode, idx);
-
-       tty = driver->ttys[idx];
-       return tty;
-}
-
-/**
- *     tty_init_termios        -  helper for termios setup
- *     @tty: the tty to set up
- *
- *     Initialise the termios structures for this tty. Thus runs under
- *     the tty_mutex currently so we can be relaxed about ordering.
- */
-
-int tty_init_termios(struct tty_struct *tty)
-{
-       struct ktermios *tp;
-       int idx = tty->index;
-
-       tp = tty->driver->termios[idx];
-       if (tp == NULL) {
-               tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
-               if (tp == NULL)
-                       return -ENOMEM;
-               memcpy(tp, &tty->driver->init_termios,
-                                               sizeof(struct ktermios));
-               tty->driver->termios[idx] = tp;
-       }
-       tty->termios = tp;
-       tty->termios_locked = tp + 1;
-
-       /* Compatibility until drivers always set this */
-       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
-       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(tty_init_termios);
-
-/**
- *     tty_driver_install_tty() - install a tty entry in the driver
- *     @driver: the driver for the tty
- *     @tty: the tty
- *
- *     Install a tty object into the driver tables. The tty->index field
- *     will be set by the time this is called. This method is responsible
- *     for ensuring any need additional structures are allocated and
- *     configured.
- *
- *     Locking: tty_mutex for now
- */
-static int tty_driver_install_tty(struct tty_driver *driver,
-                                               struct tty_struct *tty)
-{
-       int idx = tty->index;
-       int ret;
-
-       if (driver->ops->install) {
-               ret = driver->ops->install(driver, tty);
-               return ret;
-       }
-
-       if (tty_init_termios(tty) == 0) {
-               tty_driver_kref_get(driver);
-               tty->count++;
-               driver->ttys[idx] = tty;
-               return 0;
-       }
-       return -ENOMEM;
-}
-
-/**
- *     tty_driver_remove_tty() - remove a tty from the driver tables
- *     @driver: the driver for the tty
- *     @idx:    the minor number
- *
- *     Remvoe a tty object from the driver tables. The tty->index field
- *     will be set by the time this is called.
- *
- *     Locking: tty_mutex for now
- */
-static void tty_driver_remove_tty(struct tty_driver *driver,
-                                               struct tty_struct *tty)
-{
-       if (driver->ops->remove)
-               driver->ops->remove(driver, tty);
-       else
-               driver->ttys[tty->index] = NULL;
-}
-
-/*
- *     tty_reopen()    - fast re-open of an open tty
- *     @tty    - the tty to open
- *
- *     Return 0 on success, -errno on error.
- *
- *     Locking: tty_mutex must be held from the time the tty was found
- *              till this open completes.
- */
-static int tty_reopen(struct tty_struct *tty)
-{
-       struct tty_driver *driver = tty->driver;
-
-       if (test_bit(TTY_CLOSING, &tty->flags))
-               return -EIO;
-
-       if (driver->type == TTY_DRIVER_TYPE_PTY &&
-           driver->subtype == PTY_TYPE_MASTER) {
-               /*
-                * special case for PTY masters: only one open permitted,
-                * and the slave side open count is incremented as well.
-                */
-               if (tty->count)
-                       return -EIO;
-
-               tty->link->count++;
-       }
-       tty->count++;
-       tty->driver = driver; /* N.B. why do this every time?? */
-
-       mutex_lock(&tty->ldisc_mutex);
-       WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
-       mutex_unlock(&tty->ldisc_mutex);
-
-       return 0;
-}
-
-/**
- *     tty_init_dev            -       initialise a tty device
- *     @driver: tty driver we are opening a device on
- *     @idx: device index
- *     @ret_tty: returned tty structure
- *     @first_ok: ok to open a new device (used by ptmx)
- *
- *     Prepare a tty device. This may not be a "new" clean device but
- *     could also be an active device. The pty drivers require special
- *     handling because of this.
- *
- *     Locking:
- *             The function is called under the tty_mutex, which
- *     protects us from the tty struct or driver itself going away.
- *
- *     On exit the tty device has the line discipline attached and
- *     a reference count of 1. If a pair was created for pty/tty use
- *     and the other was a pty master then it too has a reference count of 1.
- *
- * WSH 06/09/97: Rewritten to remove races and properly clean up after a
- * failed open.  The new code protects the open with a mutex, so it's
- * really quite straightforward.  The mutex locking can probably be
- * relaxed for the (most common) case of reopening a tty.
- */
-
-struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
-                                                               int first_ok)
-{
-       struct tty_struct *tty;
-       int retval;
-
-       /* Check if pty master is being opened multiple times */
-       if (driver->subtype == PTY_TYPE_MASTER &&
-               (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
-               return ERR_PTR(-EIO);
-       }
-
-       /*
-        * First time open is complex, especially for PTY devices.
-        * This code guarantees that either everything succeeds and the
-        * TTY is ready for operation, or else the table slots are vacated
-        * and the allocated memory released.  (Except that the termios
-        * and locked termios may be retained.)
-        */
-
-       if (!try_module_get(driver->owner))
-               return ERR_PTR(-ENODEV);
-
-       tty = alloc_tty_struct();
-       if (!tty)
-               goto fail_no_mem;
-       initialize_tty_struct(tty, driver, idx);
-
-       retval = tty_driver_install_tty(driver, tty);
-       if (retval < 0) {
-               free_tty_struct(tty);
-               module_put(driver->owner);
-               return ERR_PTR(retval);
-       }
-
-       /*
-        * Structures all installed ... call the ldisc open routines.
-        * If we fail here just call release_tty to clean up.  No need
-        * to decrement the use counts, as release_tty doesn't care.
-        */
-       retval = tty_ldisc_setup(tty, tty->link);
-       if (retval)
-               goto release_mem_out;
-       return tty;
-
-fail_no_mem:
-       module_put(driver->owner);
-       return ERR_PTR(-ENOMEM);
-
-       /* call the tty release_tty routine to clean out this slot */
-release_mem_out:
-       if (printk_ratelimit())
-               printk(KERN_INFO "tty_init_dev: ldisc open failed, "
-                                "clearing slot %d\n", idx);
-       release_tty(tty, idx);
-       return ERR_PTR(retval);
-}
-
-void tty_free_termios(struct tty_struct *tty)
-{
-       struct ktermios *tp;
-       int idx = tty->index;
-       /* Kill this flag and push into drivers for locking etc */
-       if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
-               /* FIXME: Locking on ->termios array */
-               tp = tty->termios;
-               tty->driver->termios[idx] = NULL;
-               kfree(tp);
-       }
-}
-EXPORT_SYMBOL(tty_free_termios);
-
-void tty_shutdown(struct tty_struct *tty)
-{
-       tty_driver_remove_tty(tty->driver, tty);
-       tty_free_termios(tty);
-}
-EXPORT_SYMBOL(tty_shutdown);
-
-/**
- *     release_one_tty         -       release tty structure memory
- *     @kref: kref of tty we are obliterating
- *
- *     Releases memory associated with a tty structure, and clears out the
- *     driver table slots. This function is called when a device is no longer
- *     in use. It also gets called when setup of a device fails.
- *
- *     Locking:
- *             tty_mutex - sometimes only
- *             takes the file list lock internally when working on the list
- *     of ttys that the driver keeps.
- *
- *     This method gets called from a work queue so that the driver private
- *     cleanup ops can sleep (needed for USB at least)
- */
-static void release_one_tty(struct work_struct *work)
-{
-       struct tty_struct *tty =
-               container_of(work, struct tty_struct, hangup_work);
-       struct tty_driver *driver = tty->driver;
-
-       if (tty->ops->cleanup)
-               tty->ops->cleanup(tty);
-
-       tty->magic = 0;
-       tty_driver_kref_put(driver);
-       module_put(driver->owner);
-
-       spin_lock(&tty_files_lock);
-       list_del_init(&tty->tty_files);
-       spin_unlock(&tty_files_lock);
-
-       put_pid(tty->pgrp);
-       put_pid(tty->session);
-       free_tty_struct(tty);
-}
-
-static void queue_release_one_tty(struct kref *kref)
-{
-       struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
-
-       if (tty->ops->shutdown)
-               tty->ops->shutdown(tty);
-       else
-               tty_shutdown(tty);
-
-       /* The hangup queue is now free so we can reuse it rather than
-          waste a chunk of memory for each port */
-       INIT_WORK(&tty->hangup_work, release_one_tty);
-       schedule_work(&tty->hangup_work);
-}
-
-/**
- *     tty_kref_put            -       release a tty kref
- *     @tty: tty device
- *
- *     Release a reference to a tty device and if need be let the kref
- *     layer destruct the object for us
- */
-
-void tty_kref_put(struct tty_struct *tty)
-{
-       if (tty)
-               kref_put(&tty->kref, queue_release_one_tty);
-}
-EXPORT_SYMBOL(tty_kref_put);
-
-/**
- *     release_tty             -       release tty structure memory
- *
- *     Release both @tty and a possible linked partner (think pty pair),
- *     and decrement the refcount of the backing module.
- *
- *     Locking:
- *             tty_mutex - sometimes only
- *             takes the file list lock internally when working on the list
- *     of ttys that the driver keeps.
- *             FIXME: should we require tty_mutex is held here ??
- *
- */
-static void release_tty(struct tty_struct *tty, int idx)
-{
-       /* This should always be true but check for the moment */
-       WARN_ON(tty->index != idx);
-
-       if (tty->link)
-               tty_kref_put(tty->link);
-       tty_kref_put(tty);
-}
-
-/**
- *     tty_release             -       vfs callback for close
- *     @inode: inode of tty
- *     @filp: file pointer for handle to tty
- *
- *     Called the last time each file handle is closed that references
- *     this tty. There may however be several such references.
- *
- *     Locking:
- *             Takes bkl. See tty_release_dev
- *
- * Even releasing the tty structures is a tricky business.. We have
- * to be very careful that the structures are all released at the
- * same time, as interrupts might otherwise get the wrong pointers.
- *
- * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
- * lead to double frees or releasing memory still in use.
- */
-
-int tty_release(struct inode *inode, struct file *filp)
-{
-       struct tty_struct *tty = file_tty(filp);
-       struct tty_struct *o_tty;
-       int     pty_master, tty_closing, o_tty_closing, do_sleep;
-       int     devpts;
-       int     idx;
-       char    buf[64];
-
-       if (tty_paranoia_check(tty, inode, "tty_release_dev"))
-               return 0;
-
-       tty_lock();
-       check_tty_count(tty, "tty_release_dev");
-
-       __tty_fasync(-1, filp, 0);
-
-       idx = tty->index;
-       pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-                     tty->driver->subtype == PTY_TYPE_MASTER);
-       devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
-       o_tty = tty->link;
-
-#ifdef TTY_PARANOIA_CHECK
-       if (idx < 0 || idx >= tty->driver->num) {
-               printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
-                                 "free (%s)\n", tty->name);
-               tty_unlock();
-               return 0;
-       }
-       if (!devpts) {
-               if (tty != tty->driver->ttys[idx]) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
-                              "for (%s)\n", idx, tty->name);
-                       return 0;
-               }
-               if (tty->termios != tty->driver->termios[idx]) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
-                              "for (%s)\n",
-                              idx, tty->name);
-                       return 0;
-               }
-       }
-#endif
-
-#ifdef TTY_DEBUG_HANGUP
-       printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...",
-              tty_name(tty, buf), tty->count);
-#endif
-
-#ifdef TTY_PARANOIA_CHECK
-       if (tty->driver->other &&
-            !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
-               if (o_tty != tty->driver->other->ttys[idx]) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
-                                         "not o_tty for (%s)\n",
-                              idx, tty->name);
-                       return 0 ;
-               }
-               if (o_tty->termios != tty->driver->other->termios[idx]) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
-                                         "not o_termios for (%s)\n",
-                              idx, tty->name);
-                       return 0;
-               }
-               if (o_tty->link != tty) {
-                       tty_unlock();
-                       printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
-                       return 0;
-               }
-       }
-#endif
-       if (tty->ops->close)
-               tty->ops->close(tty, filp);
-
-       tty_unlock();
-       /*
-        * Sanity check: if tty->count is going to zero, there shouldn't be
-        * any waiters on tty->read_wait or tty->write_wait.  We test the
-        * wait queues and kick everyone out _before_ actually starting to
-        * close.  This ensures that we won't block while releasing the tty
-        * structure.
-        *
-        * The test for the o_tty closing is necessary, since the master and
-        * slave sides may close in any order.  If the slave side closes out
-        * first, its count will be one, since the master side holds an open.
-        * Thus this test wouldn't be triggered at the time the slave closes,
-        * so we do it now.
-        *
-        * Note that it's possible for the tty to be opened again while we're
-        * flushing out waiters.  By recalculating the closing flags before
-        * each iteration we avoid any problems.
-        */
-       while (1) {
-               /* Guard against races with tty->count changes elsewhere and
-                  opens on /dev/tty */
-
-               mutex_lock(&tty_mutex);
-               tty_lock();
-               tty_closing = tty->count <= 1;
-               o_tty_closing = o_tty &&
-                       (o_tty->count <= (pty_master ? 1 : 0));
-               do_sleep = 0;
-
-               if (tty_closing) {
-                       if (waitqueue_active(&tty->read_wait)) {
-                               wake_up_poll(&tty->read_wait, POLLIN);
-                               do_sleep++;
-                       }
-                       if (waitqueue_active(&tty->write_wait)) {
-                               wake_up_poll(&tty->write_wait, POLLOUT);
-                               do_sleep++;
-                       }
-               }
-               if (o_tty_closing) {
-                       if (waitqueue_active(&o_tty->read_wait)) {
-                               wake_up_poll(&o_tty->read_wait, POLLIN);
-                               do_sleep++;
-                       }
-                       if (waitqueue_active(&o_tty->write_wait)) {
-                               wake_up_poll(&o_tty->write_wait, POLLOUT);
-                               do_sleep++;
-                       }
-               }
-               if (!do_sleep)
-                       break;
-
-               printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
-                                   "active!\n", tty_name(tty, buf));
-               tty_unlock();
-               mutex_unlock(&tty_mutex);
-               schedule();
-       }
-
-       /*
-        * The closing flags are now consistent with the open counts on
-        * both sides, and we've completed the last operation that could
-        * block, so it's safe to proceed with closing.
-        */
-       if (pty_master) {
-               if (--o_tty->count < 0) {
-                       printk(KERN_WARNING "tty_release_dev: bad pty slave count "
-                                           "(%d) for %s\n",
-                              o_tty->count, tty_name(o_tty, buf));
-                       o_tty->count = 0;
-               }
-       }
-       if (--tty->count < 0) {
-               printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n",
-                      tty->count, tty_name(tty, buf));
-               tty->count = 0;
-       }
-
-       /*
-        * We've decremented tty->count, so we need to remove this file
-        * descriptor off the tty->tty_files list; this serves two
-        * purposes:
-        *  - check_tty_count sees the correct number of file descriptors
-        *    associated with this tty.
-        *  - do_tty_hangup no longer sees this file descriptor as
-        *    something that needs to be handled for hangups.
-        */
-       tty_del_file(filp);
-
-       /*
-        * Perform some housekeeping before deciding whether to return.
-        *
-        * Set the TTY_CLOSING flag if this was the last open.  In the
-        * case of a pty we may have to wait around for the other side
-        * to close, and TTY_CLOSING makes sure we can't be reopened.
-        */
-       if (tty_closing)
-               set_bit(TTY_CLOSING, &tty->flags);
-       if (o_tty_closing)
-               set_bit(TTY_CLOSING, &o_tty->flags);
-
-       /*
-        * If _either_ side is closing, make sure there aren't any
-        * processes that still think tty or o_tty is their controlling
-        * tty.
-        */
-       if (tty_closing || o_tty_closing) {
-               read_lock(&tasklist_lock);
-               session_clear_tty(tty->session);
-               if (o_tty)
-                       session_clear_tty(o_tty->session);
-               read_unlock(&tasklist_lock);
-       }
-
-       mutex_unlock(&tty_mutex);
-
-       /* check whether both sides are closing ... */
-       if (!tty_closing || (o_tty && !o_tty_closing)) {
-               tty_unlock();
-               return 0;
-       }
-
-#ifdef TTY_DEBUG_HANGUP
-       printk(KERN_DEBUG "freeing tty structure...");
-#endif
-       /*
-        * Ask the line discipline code to release its structures
-        */
-       tty_ldisc_release(tty, o_tty);
-       /*
-        * The release_tty function takes care of the details of clearing
-        * the slots and preserving the termios structure.
-        */
-       release_tty(tty, idx);
-
-       /* Make this pty number available for reallocation */
-       if (devpts)
-               devpts_kill_index(inode, idx);
-       tty_unlock();
-       return 0;
-}
-
-/**
- *     tty_open                -       open a tty device
- *     @inode: inode of device file
- *     @filp: file pointer to tty
- *
- *     tty_open and tty_release keep up the tty count that contains the
- *     number of opens done on a tty. We cannot use the inode-count, as
- *     different inodes might point to the same tty.
- *
- *     Open-counting is needed for pty masters, as well as for keeping
- *     track of serial lines: DTR is dropped when the last close happens.
- *     (This is not done solely through tty->count, now.  - Ted 1/27/92)
- *
- *     The termios state of a pty is reset on first open so that
- *     settings don't persist across reuse.
- *
- *     Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work.
- *              tty->count should protect the rest.
- *              ->siglock protects ->signal/->sighand
- */
-
-static int tty_open(struct inode *inode, struct file *filp)
-{
-       struct tty_struct *tty = NULL;
-       int noctty, retval;
-       struct tty_driver *driver;
-       int index;
-       dev_t device = inode->i_rdev;
-       unsigned saved_flags = filp->f_flags;
-
-       nonseekable_open(inode, filp);
-
-retry_open:
-       noctty = filp->f_flags & O_NOCTTY;
-       index  = -1;
-       retval = 0;
-
-       mutex_lock(&tty_mutex);
-       tty_lock();
-
-       if (device == MKDEV(TTYAUX_MAJOR, 0)) {
-               tty = get_current_tty();
-               if (!tty) {
-                       tty_unlock();
-                       mutex_unlock(&tty_mutex);
-                       return -ENXIO;
-               }
-               driver = tty_driver_kref_get(tty->driver);
-               index = tty->index;
-               filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
-               /* noctty = 1; */
-               /* FIXME: Should we take a driver reference ? */
-               tty_kref_put(tty);
-               goto got_driver;
-       }
-#ifdef CONFIG_VT
-       if (device == MKDEV(TTY_MAJOR, 0)) {
-               extern struct tty_driver *console_driver;
-               driver = tty_driver_kref_get(console_driver);
-               index = fg_console;
-               noctty = 1;
-               goto got_driver;
-       }
-#endif
-       if (device == MKDEV(TTYAUX_MAJOR, 1)) {
-               struct tty_driver *console_driver = console_device(&index);
-               if (console_driver) {
-                       driver = tty_driver_kref_get(console_driver);
-                       if (driver) {
-                               /* Don't let /dev/console block */
-                               filp->f_flags |= O_NONBLOCK;
-                               noctty = 1;
-                               goto got_driver;
-                       }
-               }
-               tty_unlock();
-               mutex_unlock(&tty_mutex);
-               return -ENODEV;
-       }
-
-       driver = get_tty_driver(device, &index);
-       if (!driver) {
-               tty_unlock();
-               mutex_unlock(&tty_mutex);
-               return -ENODEV;
-       }
-got_driver:
-       if (!tty) {
-               /* check whether we're reopening an existing tty */
-               tty = tty_driver_lookup_tty(driver, inode, index);
-
-               if (IS_ERR(tty)) {
-                       tty_unlock();
-                       mutex_unlock(&tty_mutex);
-                       return PTR_ERR(tty);
-               }
-       }
-
-       if (tty) {
-               retval = tty_reopen(tty);
-               if (retval)
-                       tty = ERR_PTR(retval);
-       } else
-               tty = tty_init_dev(driver, index, 0);
-
-       mutex_unlock(&tty_mutex);
-       tty_driver_kref_put(driver);
-       if (IS_ERR(tty)) {
-               tty_unlock();
-               return PTR_ERR(tty);
-       }
-
-       retval = tty_add_file(tty, filp);
-       if (retval) {
-               tty_unlock();
-               return retval;
-       }
-
-       check_tty_count(tty, "tty_open");
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-           tty->driver->subtype == PTY_TYPE_MASTER)
-               noctty = 1;
-#ifdef TTY_DEBUG_HANGUP
-       printk(KERN_DEBUG "opening %s...", tty->name);
-#endif
-       if (!retval) {
-               if (tty->ops->open)
-                       retval = tty->ops->open(tty, filp);
-               else
-                       retval = -ENODEV;
-       }
-       filp->f_flags = saved_flags;
-
-       if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) &&
-                                               !capable(CAP_SYS_ADMIN))
-               retval = -EBUSY;
-
-       if (retval) {
-#ifdef TTY_DEBUG_HANGUP
-               printk(KERN_DEBUG "error %d in opening %s...", retval,
-                      tty->name);
-#endif
-               tty_unlock(); /* need to call tty_release without BTM */
-               tty_release(inode, filp);
-               if (retval != -ERESTARTSYS)
-                       return retval;
-
-               if (signal_pending(current))
-                       return retval;
-
-               schedule();
-               /*
-                * Need to reset f_op in case a hangup happened.
-                */
-               tty_lock();
-               if (filp->f_op == &hung_up_tty_fops)
-                       filp->f_op = &tty_fops;
-               tty_unlock();
-               goto retry_open;
-       }
-       tty_unlock();
-
-
-       mutex_lock(&tty_mutex);
-       tty_lock();
-       spin_lock_irq(&current->sighand->siglock);
-       if (!noctty &&
-           current->signal->leader &&
-           !current->signal->tty &&
-           tty->session == NULL)
-               __proc_set_tty(current, tty);
-       spin_unlock_irq(&current->sighand->siglock);
-       tty_unlock();
-       mutex_unlock(&tty_mutex);
-       return 0;
-}
-
-
-
-/**
- *     tty_poll        -       check tty status
- *     @filp: file being polled
- *     @wait: poll wait structures to update
- *
- *     Call the line discipline polling method to obtain the poll
- *     status of the device.
- *
- *     Locking: locks called line discipline but ldisc poll method
- *     may be re-entered freely by other callers.
- */
-
-static unsigned int tty_poll(struct file *filp, poll_table *wait)
-{
-       struct tty_struct *tty = file_tty(filp);
-       struct tty_ldisc *ld;
-       int ret = 0;
-
-       if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_poll"))
-               return 0;
-
-       ld = tty_ldisc_ref_wait(tty);
-       if (ld->ops->poll)
-               ret = (ld->ops->poll)(tty, filp, wait);
-       tty_ldisc_deref(ld);
-       return ret;
-}
-
-static int __tty_fasync(int fd, struct file *filp, int on)
-{
-       struct tty_struct *tty = file_tty(filp);
-       unsigned long flags;
-       int retval = 0;
-
-       if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync"))
-               goto out;
-
-       retval = fasync_helper(fd, filp, on, &tty->fasync);
-       if (retval <= 0)
-               goto out;
-
-       if (on) {
-               enum pid_type type;
-               struct pid *pid;
-               if (!waitqueue_active(&tty->read_wait))
-                       tty->minimum_to_wake = 1;
-               spin_lock_irqsave(&tty->ctrl_lock, flags);
-               if (tty->pgrp) {
-                       pid = tty->pgrp;
-                       type = PIDTYPE_PGID;
-               } else {
-                       pid = task_pid(current);
-                       type = PIDTYPE_PID;
-               }
-               get_pid(pid);
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               retval = __f_setown(filp, pid, type, 0);
-               put_pid(pid);
-               if (retval)
-                       goto out;
-       } else {
-               if (!tty->fasync && !waitqueue_active(&tty->read_wait))
-                       tty->minimum_to_wake = N_TTY_BUF_SIZE;
-       }
-       retval = 0;
-out:
-       return retval;
-}
-
-static int tty_fasync(int fd, struct file *filp, int on)
-{
-       int retval;
-       tty_lock();
-       retval = __tty_fasync(fd, filp, on);
-       tty_unlock();
-       return retval;
-}
-
-/**
- *     tiocsti                 -       fake input character
- *     @tty: tty to fake input into
- *     @p: pointer to character
- *
- *     Fake input to a tty device. Does the necessary locking and
- *     input management.
- *
- *     FIXME: does not honour flow control ??
- *
- *     Locking:
- *             Called functions take tty_ldisc_lock
- *             current->signal->tty check is safe without locks
- *
- *     FIXME: may race normal receive processing
- */
-
-static int tiocsti(struct tty_struct *tty, char __user *p)
-{
-       char ch, mbz = 0;
-       struct tty_ldisc *ld;
-
-       if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       if (get_user(ch, p))
-               return -EFAULT;
-       tty_audit_tiocsti(tty, ch);
-       ld = tty_ldisc_ref_wait(tty);
-       ld->ops->receive_buf(tty, &ch, &mbz, 1);
-       tty_ldisc_deref(ld);
-       return 0;
-}
-
-/**
- *     tiocgwinsz              -       implement window query ioctl
- *     @tty; tty
- *     @arg: user buffer for result
- *
- *     Copies the kernel idea of the window size into the user buffer.
- *
- *     Locking: tty->termios_mutex is taken to ensure the winsize data
- *             is consistent.
- */
-
-static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
-{
-       int err;
-
-       mutex_lock(&tty->termios_mutex);
-       err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
-       mutex_unlock(&tty->termios_mutex);
-
-       return err ? -EFAULT: 0;
-}
-
-/**
- *     tty_do_resize           -       resize event
- *     @tty: tty being resized
- *     @rows: rows (character)
- *     @cols: cols (character)
- *
- *     Update the termios variables and send the necessary signals to
- *     peform a terminal resize correctly
- */
-
-int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
-{
-       struct pid *pgrp;
-       unsigned long flags;
-
-       /* Lock the tty */
-       mutex_lock(&tty->termios_mutex);
-       if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
-               goto done;
-       /* Get the PID values and reference them so we can
-          avoid holding the tty ctrl lock while sending signals */
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       pgrp = get_pid(tty->pgrp);
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
-       if (pgrp)
-               kill_pgrp(pgrp, SIGWINCH, 1);
-       put_pid(pgrp);
-
-       tty->winsize = *ws;
-done:
-       mutex_unlock(&tty->termios_mutex);
-       return 0;
-}
-
-/**
- *     tiocswinsz              -       implement window size set ioctl
- *     @tty; tty side of tty
- *     @arg: user buffer for result
- *
- *     Copies the user idea of the window size to the kernel. Traditionally
- *     this is just advisory information but for the Linux console it
- *     actually has driver level meaning and triggers a VC resize.
- *
- *     Locking:
- *             Driver dependant. The default do_resize method takes the
- *     tty termios mutex and ctrl_lock. The console takes its own lock
- *     then calls into the default method.
- */
-
-static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg)
-{
-       struct winsize tmp_ws;
-       if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
-               return -EFAULT;
-
-       if (tty->ops->resize)
-               return tty->ops->resize(tty, &tmp_ws);
-       else
-               return tty_do_resize(tty, &tmp_ws);
-}
-
-/**
- *     tioccons        -       allow admin to move logical console
- *     @file: the file to become console
- *
- *     Allow the adminstrator to move the redirected console device
- *
- *     Locking: uses redirect_lock to guard the redirect information
- */
-
-static int tioccons(struct file *file)
-{
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       if (file->f_op->write == redirected_tty_write) {
-               struct file *f;
-               spin_lock(&redirect_lock);
-               f = redirect;
-               redirect = NULL;
-               spin_unlock(&redirect_lock);
-               if (f)
-                       fput(f);
-               return 0;
-       }
-       spin_lock(&redirect_lock);
-       if (redirect) {
-               spin_unlock(&redirect_lock);
-               return -EBUSY;
-       }
-       get_file(file);
-       redirect = file;
-       spin_unlock(&redirect_lock);
-       return 0;
-}
-
-/**
- *     fionbio         -       non blocking ioctl
- *     @file: file to set blocking value
- *     @p: user parameter
- *
- *     Historical tty interfaces had a blocking control ioctl before
- *     the generic functionality existed. This piece of history is preserved
- *     in the expected tty API of posix OS's.
- *
- *     Locking: none, the open file handle ensures it won't go away.
- */
-
-static int fionbio(struct file *file, int __user *p)
-{
-       int nonblock;
-
-       if (get_user(nonblock, p))
-               return -EFAULT;
-
-       spin_lock(&file->f_lock);
-       if (nonblock)
-               file->f_flags |= O_NONBLOCK;
-       else
-               file->f_flags &= ~O_NONBLOCK;
-       spin_unlock(&file->f_lock);
-       return 0;
-}
-
-/**
- *     tiocsctty       -       set controlling tty
- *     @tty: tty structure
- *     @arg: user argument
- *
- *     This ioctl is used to manage job control. It permits a session
- *     leader to set this tty as the controlling tty for the session.
- *
- *     Locking:
- *             Takes tty_mutex() to protect tty instance
- *             Takes tasklist_lock internally to walk sessions
- *             Takes ->siglock() when updating signal->tty
- */
-
-static int tiocsctty(struct tty_struct *tty, int arg)
-{
-       int ret = 0;
-       if (current->signal->leader && (task_session(current) == tty->session))
-               return ret;
-
-       mutex_lock(&tty_mutex);
-       /*
-        * The process must be a session leader and
-        * not have a controlling tty already.
-        */
-       if (!current->signal->leader || current->signal->tty) {
-               ret = -EPERM;
-               goto unlock;
-       }
-
-       if (tty->session) {
-               /*
-                * This tty is already the controlling
-                * tty for another session group!
-                */
-               if (arg == 1 && capable(CAP_SYS_ADMIN)) {
-                       /*
-                        * Steal it away
-                        */
-                       read_lock(&tasklist_lock);
-                       session_clear_tty(tty->session);
-                       read_unlock(&tasklist_lock);
-               } else {
-                       ret = -EPERM;
-                       goto unlock;
-               }
-       }
-       proc_set_tty(current, tty);
-unlock:
-       mutex_unlock(&tty_mutex);
-       return ret;
-}
-
-/**
- *     tty_get_pgrp    -       return a ref counted pgrp pid
- *     @tty: tty to read
- *
- *     Returns a refcounted instance of the pid struct for the process
- *     group controlling the tty.
- */
-
-struct pid *tty_get_pgrp(struct tty_struct *tty)
-{
-       unsigned long flags;
-       struct pid *pgrp;
-
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       pgrp = get_pid(tty->pgrp);
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
-       return pgrp;
-}
-EXPORT_SYMBOL_GPL(tty_get_pgrp);
-
-/**
- *     tiocgpgrp               -       get process group
- *     @tty: tty passed by user
- *     @real_tty: tty side of the tty pased by the user if a pty else the tty
- *     @p: returned pid
- *
- *     Obtain the process group of the tty. If there is no process group
- *     return an error.
- *
- *     Locking: none. Reference to current->signal->tty is safe.
- */
-
-static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
-{
-       struct pid *pid;
-       int ret;
-       /*
-        * (tty == real_tty) is a cheap way of
-        * testing if the tty is NOT a master pty.
-        */
-       if (tty == real_tty && current->signal->tty != real_tty)
-               return -ENOTTY;
-       pid = tty_get_pgrp(real_tty);
-       ret =  put_user(pid_vnr(pid), p);
-       put_pid(pid);
-       return ret;
-}
-
-/**
- *     tiocspgrp               -       attempt to set process group
- *     @tty: tty passed by user
- *     @real_tty: tty side device matching tty passed by user
- *     @p: pid pointer
- *
- *     Set the process group of the tty to the session passed. Only
- *     permitted where the tty session is our session.
- *
- *     Locking: RCU, ctrl lock
- */
-
-static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
-{
-       struct pid *pgrp;
-       pid_t pgrp_nr;
-       int retval = tty_check_change(real_tty);
-       unsigned long flags;
-
-       if (retval == -EIO)
-               return -ENOTTY;
-       if (retval)
-               return retval;
-       if (!current->signal->tty ||
-           (current->signal->tty != real_tty) ||
-           (real_tty->session != task_session(current)))
-               return -ENOTTY;
-       if (get_user(pgrp_nr, p))
-               return -EFAULT;
-       if (pgrp_nr < 0)
-               return -EINVAL;
-       rcu_read_lock();
-       pgrp = find_vpid(pgrp_nr);
-       retval = -ESRCH;
-       if (!pgrp)
-               goto out_unlock;
-       retval = -EPERM;
-       if (session_of_pgrp(pgrp) != task_session(current))
-               goto out_unlock;
-       retval = 0;
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       put_pid(real_tty->pgrp);
-       real_tty->pgrp = get_pid(pgrp);
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-out_unlock:
-       rcu_read_unlock();
-       return retval;
-}
-
-/**
- *     tiocgsid                -       get session id
- *     @tty: tty passed by user
- *     @real_tty: tty side of the tty pased by the user if a pty else the tty
- *     @p: pointer to returned session id
- *
- *     Obtain the session id of the tty. If there is no session
- *     return an error.
- *
- *     Locking: none. Reference to current->signal->tty is safe.
- */
-
-static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
-{
-       /*
-        * (tty == real_tty) is a cheap way of
-        * testing if the tty is NOT a master pty.
-       */
-       if (tty == real_tty && current->signal->tty != real_tty)
-               return -ENOTTY;
-       if (!real_tty->session)
-               return -ENOTTY;
-       return put_user(pid_vnr(real_tty->session), p);
-}
-
-/**
- *     tiocsetd        -       set line discipline
- *     @tty: tty device
- *     @p: pointer to user data
- *
- *     Set the line discipline according to user request.
- *
- *     Locking: see tty_set_ldisc, this function is just a helper
- */
-
-static int tiocsetd(struct tty_struct *tty, int __user *p)
-{
-       int ldisc;
-       int ret;
-
-       if (get_user(ldisc, p))
-               return -EFAULT;
-
-       ret = tty_set_ldisc(tty, ldisc);
-
-       return ret;
-}
-
-/**
- *     send_break      -       performed time break
- *     @tty: device to break on
- *     @duration: timeout in mS
- *
- *     Perform a timed break on hardware that lacks its own driver level
- *     timed break functionality.
- *
- *     Locking:
- *             atomic_write_lock serializes
- *
- */
-
-static int send_break(struct tty_struct *tty, unsigned int duration)
-{
-       int retval;
-
-       if (tty->ops->break_ctl == NULL)
-               return 0;
-
-       if (tty->driver->flags & TTY_DRIVER_HARDWARE_BREAK)
-               retval = tty->ops->break_ctl(tty, duration);
-       else {
-               /* Do the work ourselves */
-               if (tty_write_lock(tty, 0) < 0)
-                       return -EINTR;
-               retval = tty->ops->break_ctl(tty, -1);
-               if (retval)
-                       goto out;
-               if (!signal_pending(current))
-                       msleep_interruptible(duration);
-               retval = tty->ops->break_ctl(tty, 0);
-out:
-               tty_write_unlock(tty);
-               if (signal_pending(current))
-                       retval = -EINTR;
-       }
-       return retval;
-}
-
-/**
- *     tty_tiocmget            -       get modem status
- *     @tty: tty device
- *     @file: user file pointer
- *     @p: pointer to result
- *
- *     Obtain the modem status bits from the tty driver if the feature
- *     is supported. Return -EINVAL if it is not available.
- *
- *     Locking: none (up to the driver)
- */
-
-static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p)
-{
-       int retval = -EINVAL;
-
-       if (tty->ops->tiocmget) {
-               retval = tty->ops->tiocmget(tty, file);
-
-               if (retval >= 0)
-                       retval = put_user(retval, p);
-       }
-       return retval;
-}
-
-/**
- *     tty_tiocmset            -       set modem status
- *     @tty: tty device
- *     @file: user file pointer
- *     @cmd: command - clear bits, set bits or set all
- *     @p: pointer to desired bits
- *
- *     Set the modem status bits from the tty driver if the feature
- *     is supported. Return -EINVAL if it is not available.
- *
- *     Locking: none (up to the driver)
- */
-
-static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd,
-            unsigned __user *p)
-{
-       int retval;
-       unsigned int set, clear, val;
-
-       if (tty->ops->tiocmset == NULL)
-               return -EINVAL;
-
-       retval = get_user(val, p);
-       if (retval)
-               return retval;
-       set = clear = 0;
-       switch (cmd) {
-       case TIOCMBIS:
-               set = val;
-               break;
-       case TIOCMBIC:
-               clear = val;
-               break;
-       case TIOCMSET:
-               set = val;
-               clear = ~val;
-               break;
-       }
-       set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
-       clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
-       return tty->ops->tiocmset(tty, file, set, clear);
-}
-
-static int tty_tiocgicount(struct tty_struct *tty, void __user *arg)
-{
-       int retval = -EINVAL;
-       struct serial_icounter_struct icount;
-       memset(&icount, 0, sizeof(icount));
-       if (tty->ops->get_icount)
-               retval = tty->ops->get_icount(tty, &icount);
-       if (retval != 0)
-               return retval;
-       if (copy_to_user(arg, &icount, sizeof(icount)))
-               return -EFAULT;
-       return 0;
-}
-
-struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
-{
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-           tty->driver->subtype == PTY_TYPE_MASTER)
-               tty = tty->link;
-       return tty;
-}
-EXPORT_SYMBOL(tty_pair_get_tty);
-
-struct tty_struct *tty_pair_get_pty(struct tty_struct *tty)
-{
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-           tty->driver->subtype == PTY_TYPE_MASTER)
-           return tty;
-       return tty->link;
-}
-EXPORT_SYMBOL(tty_pair_get_pty);
-
-/*
- * Split this up, as gcc can choke on it otherwise..
- */
-long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-       struct tty_struct *tty = file_tty(file);
-       struct tty_struct *real_tty;
-       void __user *p = (void __user *)arg;
-       int retval;
-       struct tty_ldisc *ld;
-       struct inode *inode = file->f_dentry->d_inode;
-
-       if (tty_paranoia_check(tty, inode, "tty_ioctl"))
-               return -EINVAL;
-
-       real_tty = tty_pair_get_tty(tty);
-
-       /*
-        * Factor out some common prep work
-        */
-       switch (cmd) {
-       case TIOCSETD:
-       case TIOCSBRK:
-       case TIOCCBRK:
-       case TCSBRK:
-       case TCSBRKP:
-               retval = tty_check_change(tty);
-               if (retval)
-                       return retval;
-               if (cmd != TIOCCBRK) {
-                       tty_wait_until_sent(tty, 0);
-                       if (signal_pending(current))
-                               return -EINTR;
-               }
-               break;
-       }
-
-       /*
-        *      Now do the stuff.
-        */
-       switch (cmd) {
-       case TIOCSTI:
-               return tiocsti(tty, p);
-       case TIOCGWINSZ:
-               return tiocgwinsz(real_tty, p);
-       case TIOCSWINSZ:
-               return tiocswinsz(real_tty, p);
-       case TIOCCONS:
-               return real_tty != tty ? -EINVAL : tioccons(file);
-       case FIONBIO:
-               return fionbio(file, p);
-       case TIOCEXCL:
-               set_bit(TTY_EXCLUSIVE, &tty->flags);
-               return 0;
-       case TIOCNXCL:
-               clear_bit(TTY_EXCLUSIVE, &tty->flags);
-               return 0;
-       case TIOCNOTTY:
-               if (current->signal->tty != tty)
-                       return -ENOTTY;
-               no_tty();
-               return 0;
-       case TIOCSCTTY:
-               return tiocsctty(tty, arg);
-       case TIOCGPGRP:
-               return tiocgpgrp(tty, real_tty, p);
-       case TIOCSPGRP:
-               return tiocspgrp(tty, real_tty, p);
-       case TIOCGSID:
-               return tiocgsid(tty, real_tty, p);
-       case TIOCGETD:
-               return put_user(tty->ldisc->ops->num, (int __user *)p);
-       case TIOCSETD:
-               return tiocsetd(tty, p);
-       /*
-        * Break handling
-        */
-       case TIOCSBRK:  /* Turn break on, unconditionally */
-               if (tty->ops->break_ctl)
-                       return tty->ops->break_ctl(tty, -1);
-               return 0;
-       case TIOCCBRK:  /* Turn break off, unconditionally */
-               if (tty->ops->break_ctl)
-                       return tty->ops->break_ctl(tty, 0);
-               return 0;
-       case TCSBRK:   /* SVID version: non-zero arg --> no break */
-               /* non-zero arg means wait for all output data
-                * to be sent (performed above) but don't send break.
-                * This is used by the tcdrain() termios function.
-                */
-               if (!arg)
-                       return send_break(tty, 250);
-               return 0;
-       case TCSBRKP:   /* support for POSIX tcsendbreak() */
-               return send_break(tty, arg ? arg*100 : 250);
-
-       case TIOCMGET:
-               return tty_tiocmget(tty, file, p);
-       case TIOCMSET:
-       case TIOCMBIC:
-       case TIOCMBIS:
-               return tty_tiocmset(tty, file, cmd, p);
-       case TIOCGICOUNT:
-               retval = tty_tiocgicount(tty, p);
-               /* For the moment allow fall through to the old method */
-               if (retval != -EINVAL)
-                       return retval;
-               break;
-       case TCFLSH:
-               switch (arg) {
-               case TCIFLUSH:
-               case TCIOFLUSH:
-               /* flush tty buffer and allow ldisc to process ioctl */
-                       tty_buffer_flush(tty);
-                       break;
-               }
-               break;
-       }
-       if (tty->ops->ioctl) {
-               retval = (tty->ops->ioctl)(tty, file, cmd, arg);
-               if (retval != -ENOIOCTLCMD)
-                       return retval;
-       }
-       ld = tty_ldisc_ref_wait(tty);
-       retval = -EINVAL;
-       if (ld->ops->ioctl) {
-               retval = ld->ops->ioctl(tty, file, cmd, arg);
-               if (retval == -ENOIOCTLCMD)
-                       retval = -EINVAL;
-       }
-       tty_ldisc_deref(ld);
-       return retval;
-}
-
-#ifdef CONFIG_COMPAT
-static long tty_compat_ioctl(struct file *file, unsigned int cmd,
-                               unsigned long arg)
-{
-       struct inode *inode = file->f_dentry->d_inode;
-       struct tty_struct *tty = file_tty(file);
-       struct tty_ldisc *ld;
-       int retval = -ENOIOCTLCMD;
-
-       if (tty_paranoia_check(tty, inode, "tty_ioctl"))
-               return -EINVAL;
-
-       if (tty->ops->compat_ioctl) {
-               retval = (tty->ops->compat_ioctl)(tty, file, cmd, arg);
-               if (retval != -ENOIOCTLCMD)
-                       return retval;
-       }
-
-       ld = tty_ldisc_ref_wait(tty);
-       if (ld->ops->compat_ioctl)
-               retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
-       tty_ldisc_deref(ld);
-
-       return retval;
-}
-#endif
-
-/*
- * This implements the "Secure Attention Key" ---  the idea is to
- * prevent trojan horses by killing all processes associated with this
- * tty when the user hits the "Secure Attention Key".  Required for
- * super-paranoid applications --- see the Orange Book for more details.
- *
- * This code could be nicer; ideally it should send a HUP, wait a few
- * seconds, then send a INT, and then a KILL signal.  But you then
- * have to coordinate with the init process, since all processes associated
- * with the current tty must be dead before the new getty is allowed
- * to spawn.
- *
- * Now, if it would be correct ;-/ The current code has a nasty hole -
- * it doesn't catch files in flight. We may send the descriptor to ourselves
- * via AF_UNIX socket, close it and later fetch from socket. FIXME.
- *
- * Nasty bug: do_SAK is being called in interrupt context.  This can
- * deadlock.  We punt it up to process context.  AKPM - 16Mar2001
- */
-void __do_SAK(struct tty_struct *tty)
-{
-#ifdef TTY_SOFT_SAK
-       tty_hangup(tty);
-#else
-       struct task_struct *g, *p;
-       struct pid *session;
-       int             i;
-       struct file     *filp;
-       struct fdtable *fdt;
-
-       if (!tty)
-               return;
-       session = tty->session;
-
-       tty_ldisc_flush(tty);
-
-       tty_driver_flush_buffer(tty);
-
-       read_lock(&tasklist_lock);
-       /* Kill the entire session */
-       do_each_pid_task(session, PIDTYPE_SID, p) {
-               printk(KERN_NOTICE "SAK: killed process %d"
-                       " (%s): task_session(p)==tty->session\n",
-                       task_pid_nr(p), p->comm);
-               send_sig(SIGKILL, p, 1);
-       } while_each_pid_task(session, PIDTYPE_SID, p);
-       /* Now kill any processes that happen to have the
-        * tty open.
-        */
-       do_each_thread(g, p) {
-               if (p->signal->tty == tty) {
-                       printk(KERN_NOTICE "SAK: killed process %d"
-                           " (%s): task_session(p)==tty->session\n",
-                           task_pid_nr(p), p->comm);
-                       send_sig(SIGKILL, p, 1);
-                       continue;
-               }
-               task_lock(p);
-               if (p->files) {
-                       /*
-                        * We don't take a ref to the file, so we must
-                        * hold ->file_lock instead.
-                        */
-                       spin_lock(&p->files->file_lock);
-                       fdt = files_fdtable(p->files);
-                       for (i = 0; i < fdt->max_fds; i++) {
-                               filp = fcheck_files(p->files, i);
-                               if (!filp)
-                                       continue;
-                               if (filp->f_op->read == tty_read &&
-                                   file_tty(filp) == tty) {
-                                       printk(KERN_NOTICE "SAK: killed process %d"
-                                           " (%s): fd#%d opened to the tty\n",
-                                           task_pid_nr(p), p->comm, i);
-                                       force_sig(SIGKILL, p);
-                                       break;
-                               }
-                       }
-                       spin_unlock(&p->files->file_lock);
-               }
-               task_unlock(p);
-       } while_each_thread(g, p);
-       read_unlock(&tasklist_lock);
-#endif
-}
-
-static void do_SAK_work(struct work_struct *work)
-{
-       struct tty_struct *tty =
-               container_of(work, struct tty_struct, SAK_work);
-       __do_SAK(tty);
-}
-
-/*
- * The tq handling here is a little racy - tty->SAK_work may already be queued.
- * Fortunately we don't need to worry, because if ->SAK_work is already queued,
- * the values which we write to it will be identical to the values which it
- * already has. --akpm
- */
-void do_SAK(struct tty_struct *tty)
-{
-       if (!tty)
-               return;
-       schedule_work(&tty->SAK_work);
-}
-
-EXPORT_SYMBOL(do_SAK);
-
-static int dev_match_devt(struct device *dev, void *data)
-{
-       dev_t *devt = data;
-       return dev->devt == *devt;
-}
-
-/* Must put_device() after it's unused! */
-static struct device *tty_get_device(struct tty_struct *tty)
-{
-       dev_t devt = tty_devnum(tty);
-       return class_find_device(tty_class, NULL, &devt, dev_match_devt);
-}
-
-
-/**
- *     initialize_tty_struct
- *     @tty: tty to initialize
- *
- *     This subroutine initializes a tty structure that has been newly
- *     allocated.
- *
- *     Locking: none - tty in question must not be exposed at this point
- */
-
-void initialize_tty_struct(struct tty_struct *tty,
-               struct tty_driver *driver, int idx)
-{
-       memset(tty, 0, sizeof(struct tty_struct));
-       kref_init(&tty->kref);
-       tty->magic = TTY_MAGIC;
-       tty_ldisc_init(tty);
-       tty->session = NULL;
-       tty->pgrp = NULL;
-       tty->overrun_time = jiffies;
-       tty->buf.head = tty->buf.tail = NULL;
-       tty_buffer_init(tty);
-       mutex_init(&tty->termios_mutex);
-       mutex_init(&tty->ldisc_mutex);
-       init_waitqueue_head(&tty->write_wait);
-       init_waitqueue_head(&tty->read_wait);
-       INIT_WORK(&tty->hangup_work, do_tty_hangup);
-       mutex_init(&tty->atomic_read_lock);
-       mutex_init(&tty->atomic_write_lock);
-       mutex_init(&tty->output_lock);
-       mutex_init(&tty->echo_lock);
-       spin_lock_init(&tty->read_lock);
-       spin_lock_init(&tty->ctrl_lock);
-       INIT_LIST_HEAD(&tty->tty_files);
-       INIT_WORK(&tty->SAK_work, do_SAK_work);
-
-       tty->driver = driver;
-       tty->ops = driver->ops;
-       tty->index = idx;
-       tty_line_name(driver, idx, tty->name);
-       tty->dev = tty_get_device(tty);
-}
-
-/**
- *     tty_put_char    -       write one character to a tty
- *     @tty: tty
- *     @ch: character
- *
- *     Write one byte to the tty using the provided put_char method
- *     if present. Returns the number of characters successfully output.
- *
- *     Note: the specific put_char operation in the driver layer may go
- *     away soon. Don't call it directly, use this method
- */
-
-int tty_put_char(struct tty_struct *tty, unsigned char ch)
-{
-       if (tty->ops->put_char)
-               return tty->ops->put_char(tty, ch);
-       return tty->ops->write(tty, &ch, 1);
-}
-EXPORT_SYMBOL_GPL(tty_put_char);
-
-struct class *tty_class;
-
-/**
- *     tty_register_device - register a tty device
- *     @driver: the tty driver that describes the tty device
- *     @index: the index in the tty driver for this tty device
- *     @device: a struct device that is associated with this tty device.
- *             This field is optional, if there is no known struct device
- *             for this tty device it can be set to NULL safely.
- *
- *     Returns a pointer to the struct device for this tty device
- *     (or ERR_PTR(-EFOO) on error).
- *
- *     This call is required to be made to register an individual tty device
- *     if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set.  If
- *     that bit is not set, this function should not be called by a tty
- *     driver.
- *
- *     Locking: ??
- */
-
-struct device *tty_register_device(struct tty_driver *driver, unsigned index,
-                                  struct device *device)
-{
-       char name[64];
-       dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
-
-       if (index >= driver->num) {
-               printk(KERN_ERR "Attempt to register invalid tty line number "
-                      " (%d).\n", index);
-               return ERR_PTR(-EINVAL);
-       }
-
-       if (driver->type == TTY_DRIVER_TYPE_PTY)
-               pty_line_name(driver, index, name);
-       else
-               tty_line_name(driver, index, name);
-
-       return device_create(tty_class, device, dev, NULL, name);
-}
-EXPORT_SYMBOL(tty_register_device);
-
-/**
- *     tty_unregister_device - unregister a tty device
- *     @driver: the tty driver that describes the tty device
- *     @index: the index in the tty driver for this tty device
- *
- *     If a tty device is registered with a call to tty_register_device() then
- *     this function must be called when the tty device is gone.
- *
- *     Locking: ??
- */
-
-void tty_unregister_device(struct tty_driver *driver, unsigned index)
-{
-       device_destroy(tty_class,
-               MKDEV(driver->major, driver->minor_start) + index);
-}
-EXPORT_SYMBOL(tty_unregister_device);
-
-struct tty_driver *alloc_tty_driver(int lines)
-{
-       struct tty_driver *driver;
-
-       driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
-       if (driver) {
-               kref_init(&driver->kref);
-               driver->magic = TTY_DRIVER_MAGIC;
-               driver->num = lines;
-               /* later we'll move allocation of tables here */
-       }
-       return driver;
-}
-EXPORT_SYMBOL(alloc_tty_driver);
-
-static void destruct_tty_driver(struct kref *kref)
-{
-       struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
-       int i;
-       struct ktermios *tp;
-       void *p;
-
-       if (driver->flags & TTY_DRIVER_INSTALLED) {
-               /*
-                * Free the termios and termios_locked structures because
-                * we don't want to get memory leaks when modular tty
-                * drivers are removed from the kernel.
-                */
-               for (i = 0; i < driver->num; i++) {
-                       tp = driver->termios[i];
-                       if (tp) {
-                               driver->termios[i] = NULL;
-                               kfree(tp);
-                       }
-                       if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
-                               tty_unregister_device(driver, i);
-               }
-               p = driver->ttys;
-               proc_tty_unregister_driver(driver);
-               driver->ttys = NULL;
-               driver->termios = NULL;
-               kfree(p);
-               cdev_del(&driver->cdev);
-       }
-       kfree(driver);
-}
-
-void tty_driver_kref_put(struct tty_driver *driver)
-{
-       kref_put(&driver->kref, destruct_tty_driver);
-}
-EXPORT_SYMBOL(tty_driver_kref_put);
-
-void tty_set_operations(struct tty_driver *driver,
-                       const struct tty_operations *op)
-{
-       driver->ops = op;
-};
-EXPORT_SYMBOL(tty_set_operations);
-
-void put_tty_driver(struct tty_driver *d)
-{
-       tty_driver_kref_put(d);
-}
-EXPORT_SYMBOL(put_tty_driver);
-
-/*
- * Called by a tty driver to register itself.
- */
-int tty_register_driver(struct tty_driver *driver)
-{
-       int error;
-       int i;
-       dev_t dev;
-       void **p = NULL;
-       struct device *d;
-
-       if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
-               p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
-               if (!p)
-                       return -ENOMEM;
-       }
-
-       if (!driver->major) {
-               error = alloc_chrdev_region(&dev, driver->minor_start,
-                                               driver->num, driver->name);
-               if (!error) {
-                       driver->major = MAJOR(dev);
-                       driver->minor_start = MINOR(dev);
-               }
-       } else {
-               dev = MKDEV(driver->major, driver->minor_start);
-               error = register_chrdev_region(dev, driver->num, driver->name);
-       }
-       if (error < 0) {
-               kfree(p);
-               return error;
-       }
-
-       if (p) {
-               driver->ttys = (struct tty_struct **)p;
-               driver->termios = (struct ktermios **)(p + driver->num);
-       } else {
-               driver->ttys = NULL;
-               driver->termios = NULL;
-       }
-
-       cdev_init(&driver->cdev, &tty_fops);
-       driver->cdev.owner = driver->owner;
-       error = cdev_add(&driver->cdev, dev, driver->num);
-       if (error) {
-               unregister_chrdev_region(dev, driver->num);
-               driver->ttys = NULL;
-               driver->termios = NULL;
-               kfree(p);
-               return error;
-       }
-
-       mutex_lock(&tty_mutex);
-       list_add(&driver->tty_drivers, &tty_drivers);
-       mutex_unlock(&tty_mutex);
-
-       if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
-               for (i = 0; i < driver->num; i++) {
-                       d = tty_register_device(driver, i, NULL);
-                       if (IS_ERR(d)) {
-                               error = PTR_ERR(d);
-                               goto err;
-                       }
-               }
-       }
-       proc_tty_register_driver(driver);
-       driver->flags |= TTY_DRIVER_INSTALLED;
-       return 0;
-
-err:
-       for (i--; i >= 0; i--)
-               tty_unregister_device(driver, i);
-
-       mutex_lock(&tty_mutex);
-       list_del(&driver->tty_drivers);
-       mutex_unlock(&tty_mutex);
-
-       unregister_chrdev_region(dev, driver->num);
-       driver->ttys = NULL;
-       driver->termios = NULL;
-       kfree(p);
-       return error;
-}
-
-EXPORT_SYMBOL(tty_register_driver);
-
-/*
- * Called by a tty driver to unregister itself.
- */
-int tty_unregister_driver(struct tty_driver *driver)
-{
-#if 0
-       /* FIXME */
-       if (driver->refcount)
-               return -EBUSY;
-#endif
-       unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
-                               driver->num);
-       mutex_lock(&tty_mutex);
-       list_del(&driver->tty_drivers);
-       mutex_unlock(&tty_mutex);
-       return 0;
-}
-
-EXPORT_SYMBOL(tty_unregister_driver);
-
-dev_t tty_devnum(struct tty_struct *tty)
-{
-       return MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
-}
-EXPORT_SYMBOL(tty_devnum);
-
-void proc_clear_tty(struct task_struct *p)
-{
-       unsigned long flags;
-       struct tty_struct *tty;
-       spin_lock_irqsave(&p->sighand->siglock, flags);
-       tty = p->signal->tty;
-       p->signal->tty = NULL;
-       spin_unlock_irqrestore(&p->sighand->siglock, flags);
-       tty_kref_put(tty);
-}
-
-/* Called under the sighand lock */
-
-static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
-{
-       if (tty) {
-               unsigned long flags;
-               /* We should not have a session or pgrp to put here but.... */
-               spin_lock_irqsave(&tty->ctrl_lock, flags);
-               put_pid(tty->session);
-               put_pid(tty->pgrp);
-               tty->pgrp = get_pid(task_pgrp(tsk));
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               tty->session = get_pid(task_session(tsk));
-               if (tsk->signal->tty) {
-                       printk(KERN_DEBUG "tty not NULL!!\n");
-                       tty_kref_put(tsk->signal->tty);
-               }
-       }
-       put_pid(tsk->signal->tty_old_pgrp);
-       tsk->signal->tty = tty_kref_get(tty);
-       tsk->signal->tty_old_pgrp = NULL;
-}
-
-static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
-{
-       spin_lock_irq(&tsk->sighand->siglock);
-       __proc_set_tty(tsk, tty);
-       spin_unlock_irq(&tsk->sighand->siglock);
-}
-
-struct tty_struct *get_current_tty(void)
-{
-       struct tty_struct *tty;
-       unsigned long flags;
-
-       spin_lock_irqsave(&current->sighand->siglock, flags);
-       tty = tty_kref_get(current->signal->tty);
-       spin_unlock_irqrestore(&current->sighand->siglock, flags);
-       return tty;
-}
-EXPORT_SYMBOL_GPL(get_current_tty);
-
-void tty_default_fops(struct file_operations *fops)
-{
-       *fops = tty_fops;
-}
-
-/*
- * Initialize the console device. This is called *early*, so
- * we can't necessarily depend on lots of kernel help here.
- * Just do some early initializations, and do the complex setup
- * later.
- */
-void __init console_init(void)
-{
-       initcall_t *call;
-
-       /* Setup the default TTY line discipline. */
-       tty_ldisc_begin();
-
-       /*
-        * set up the console device so that later boot sequences can
-        * inform about problems etc..
-        */
-       call = __con_initcall_start;
-       while (call < __con_initcall_end) {
-               (*call)();
-               call++;
-       }
-}
-
-static char *tty_devnode(struct device *dev, mode_t *mode)
-{
-       if (!mode)
-               return NULL;
-       if (dev->devt == MKDEV(TTYAUX_MAJOR, 0) ||
-           dev->devt == MKDEV(TTYAUX_MAJOR, 2))
-               *mode = 0666;
-       return NULL;
-}
-
-static int __init tty_class_init(void)
-{
-       tty_class = class_create(THIS_MODULE, "tty");
-       if (IS_ERR(tty_class))
-               return PTR_ERR(tty_class);
-       tty_class->devnode = tty_devnode;
-       return 0;
-}
-
-postcore_initcall(tty_class_init);
-
-/* 3/2004 jmc: why do these devices exist? */
-
-static struct cdev tty_cdev, console_cdev;
-
-/*
- * Ok, now we can initialize the rest of the tty devices and can count
- * on memory allocations, interrupts etc..
- */
-int __init tty_init(void)
-{
-       cdev_init(&tty_cdev, &tty_fops);
-       if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
-           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
-               panic("Couldn't register /dev/tty driver\n");
-       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
-                             "tty");
-
-       cdev_init(&console_cdev, &console_fops);
-       if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
-           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
-               panic("Couldn't register /dev/console driver\n");
-       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
-                             "console");
-
-#ifdef CONFIG_VT
-       vty_init(&console_fops);
-#endif
-       return 0;
-}
-
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
deleted file mode 100644 (file)
index 0c18899..0000000
+++ /dev/null
@@ -1,1179 +0,0 @@
-/*
- *  linux/drivers/char/tty_ioctl.c
- *
- *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
- *
- * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
- * which can be dynamically activated and de-activated by the line
- * discipline handling modules (like SLIP).
- */
-
-#include <linux/types.h>
-#include <linux/termios.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/tty.h>
-#include <linux/fcntl.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/bitops.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
-#undef TTY_DEBUG_WAIT_UNTIL_SENT
-
-#undef DEBUG
-
-/*
- * Internal flag options for termios setting behavior
- */
-#define TERMIOS_FLUSH  1
-#define TERMIOS_WAIT   2
-#define TERMIOS_TERMIO 4
-#define TERMIOS_OLD    8
-
-
-/**
- *     tty_chars_in_buffer     -       characters pending
- *     @tty: terminal
- *
- *     Return the number of bytes of data in the device private
- *     output queue. If no private method is supplied there is assumed
- *     to be no queue on the device.
- */
-
-int tty_chars_in_buffer(struct tty_struct *tty)
-{
-       if (tty->ops->chars_in_buffer)
-               return tty->ops->chars_in_buffer(tty);
-       else
-               return 0;
-}
-EXPORT_SYMBOL(tty_chars_in_buffer);
-
-/**
- *     tty_write_room          -       write queue space
- *     @tty: terminal
- *
- *     Return the number of bytes that can be queued to this device
- *     at the present time. The result should be treated as a guarantee
- *     and the driver cannot offer a value it later shrinks by more than
- *     the number of bytes written. If no method is provided 2K is always
- *     returned and data may be lost as there will be no flow control.
- */
-int tty_write_room(struct tty_struct *tty)
-{
-       if (tty->ops->write_room)
-               return tty->ops->write_room(tty);
-       return 2048;
-}
-EXPORT_SYMBOL(tty_write_room);
-
-/**
- *     tty_driver_flush_buffer -       discard internal buffer
- *     @tty: terminal
- *
- *     Discard the internal output buffer for this device. If no method
- *     is provided then either the buffer cannot be hardware flushed or
- *     there is no buffer driver side.
- */
-void tty_driver_flush_buffer(struct tty_struct *tty)
-{
-       if (tty->ops->flush_buffer)
-               tty->ops->flush_buffer(tty);
-}
-EXPORT_SYMBOL(tty_driver_flush_buffer);
-
-/**
- *     tty_throttle            -       flow control
- *     @tty: terminal
- *
- *     Indicate that a tty should stop transmitting data down the stack.
- *     Takes the termios mutex to protect against parallel throttle/unthrottle
- *     and also to ensure the driver can consistently reference its own
- *     termios data at this point when implementing software flow control.
- */
-
-void tty_throttle(struct tty_struct *tty)
-{
-       mutex_lock(&tty->termios_mutex);
-       /* check TTY_THROTTLED first so it indicates our state */
-       if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
-           tty->ops->throttle)
-               tty->ops->throttle(tty);
-       mutex_unlock(&tty->termios_mutex);
-}
-EXPORT_SYMBOL(tty_throttle);
-
-/**
- *     tty_unthrottle          -       flow control
- *     @tty: terminal
- *
- *     Indicate that a tty may continue transmitting data down the stack.
- *     Takes the termios mutex to protect against parallel throttle/unthrottle
- *     and also to ensure the driver can consistently reference its own
- *     termios data at this point when implementing software flow control.
- *
- *     Drivers should however remember that the stack can issue a throttle,
- *     then change flow control method, then unthrottle.
- */
-
-void tty_unthrottle(struct tty_struct *tty)
-{
-       mutex_lock(&tty->termios_mutex);
-       if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
-           tty->ops->unthrottle)
-               tty->ops->unthrottle(tty);
-       mutex_unlock(&tty->termios_mutex);
-}
-EXPORT_SYMBOL(tty_unthrottle);
-
-/**
- *     tty_wait_until_sent     -       wait for I/O to finish
- *     @tty: tty we are waiting for
- *     @timeout: how long we will wait
- *
- *     Wait for characters pending in a tty driver to hit the wire, or
- *     for a timeout to occur (eg due to flow control)
- *
- *     Locking: none
- */
-
-void tty_wait_until_sent(struct tty_struct *tty, long timeout)
-{
-#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
-       char buf[64];
-
-       printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
-#endif
-       if (!timeout)
-               timeout = MAX_SCHEDULE_TIMEOUT;
-       if (wait_event_interruptible_timeout(tty->write_wait,
-                       !tty_chars_in_buffer(tty), timeout) >= 0) {
-               if (tty->ops->wait_until_sent)
-                       tty->ops->wait_until_sent(tty, timeout);
-       }
-}
-EXPORT_SYMBOL(tty_wait_until_sent);
-
-
-/*
- *             Termios Helper Methods
- */
-
-static void unset_locked_termios(struct ktermios *termios,
-                                struct ktermios *old,
-                                struct ktermios *locked)
-{
-       int     i;
-
-#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
-
-       if (!locked) {
-               printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
-               return;
-       }
-
-       NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
-       NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
-       NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
-       NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
-       termios->c_line = locked->c_line ? old->c_line : termios->c_line;
-       for (i = 0; i < NCCS; i++)
-               termios->c_cc[i] = locked->c_cc[i] ?
-                       old->c_cc[i] : termios->c_cc[i];
-       /* FIXME: What should we do for i/ospeed */
-}
-
-/*
- * Routine which returns the baud rate of the tty
- *
- * Note that the baud_table needs to be kept in sync with the
- * include/asm/termbits.h file.
- */
-static const speed_t baud_table[] = {
-       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-       9600, 19200, 38400, 57600, 115200, 230400, 460800,
-#ifdef __sparc__
-       76800, 153600, 307200, 614400, 921600
-#else
-       500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
-       2500000, 3000000, 3500000, 4000000
-#endif
-};
-
-#ifndef __sparc__
-static const tcflag_t baud_bits[] = {
-       B0, B50, B75, B110, B134, B150, B200, B300, B600,
-       B1200, B1800, B2400, B4800, B9600, B19200, B38400,
-       B57600, B115200, B230400, B460800, B500000, B576000,
-       B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
-       B3000000, B3500000, B4000000
-};
-#else
-static const tcflag_t baud_bits[] = {
-       B0, B50, B75, B110, B134, B150, B200, B300, B600,
-       B1200, B1800, B2400, B4800, B9600, B19200, B38400,
-       B57600, B115200, B230400, B460800, B76800, B153600,
-       B307200, B614400, B921600
-};
-#endif
-
-static int n_baud_table = ARRAY_SIZE(baud_table);
-
-/**
- *     tty_termios_baud_rate
- *     @termios: termios structure
- *
- *     Convert termios baud rate data into a speed. This should be called
- *     with the termios lock held if this termios is a terminal termios
- *     structure. May change the termios data. Device drivers can call this
- *     function but should use ->c_[io]speed directly as they are updated.
- *
- *     Locking: none
- */
-
-speed_t tty_termios_baud_rate(struct ktermios *termios)
-{
-       unsigned int cbaud;
-
-       cbaud = termios->c_cflag & CBAUD;
-
-#ifdef BOTHER
-       /* Magic token for arbitary speed via c_ispeed/c_ospeed */
-       if (cbaud == BOTHER)
-               return termios->c_ospeed;
-#endif
-       if (cbaud & CBAUDEX) {
-               cbaud &= ~CBAUDEX;
-
-               if (cbaud < 1 || cbaud + 15 > n_baud_table)
-                       termios->c_cflag &= ~CBAUDEX;
-               else
-                       cbaud += 15;
-       }
-       return baud_table[cbaud];
-}
-EXPORT_SYMBOL(tty_termios_baud_rate);
-
-/**
- *     tty_termios_input_baud_rate
- *     @termios: termios structure
- *
- *     Convert termios baud rate data into a speed. This should be called
- *     with the termios lock held if this termios is a terminal termios
- *     structure. May change the termios data. Device drivers can call this
- *     function but should use ->c_[io]speed directly as they are updated.
- *
- *     Locking: none
- */
-
-speed_t tty_termios_input_baud_rate(struct ktermios *termios)
-{
-#ifdef IBSHIFT
-       unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
-
-       if (cbaud == B0)
-               return tty_termios_baud_rate(termios);
-
-       /* Magic token for arbitary speed via c_ispeed*/
-       if (cbaud == BOTHER)
-               return termios->c_ispeed;
-
-       if (cbaud & CBAUDEX) {
-               cbaud &= ~CBAUDEX;
-
-               if (cbaud < 1 || cbaud + 15 > n_baud_table)
-                       termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
-               else
-                       cbaud += 15;
-       }
-       return baud_table[cbaud];
-#else
-       return tty_termios_baud_rate(termios);
-#endif
-}
-EXPORT_SYMBOL(tty_termios_input_baud_rate);
-
-/**
- *     tty_termios_encode_baud_rate
- *     @termios: ktermios structure holding user requested state
- *     @ispeed: input speed
- *     @ospeed: output speed
- *
- *     Encode the speeds set into the passed termios structure. This is
- *     used as a library helper for drivers os that they can report back
- *     the actual speed selected when it differs from the speed requested
- *
- *     For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
- *     we need to carefully set the bits when the user does not get the
- *     desired speed. We allow small margins and preserve as much of possible
- *     of the input intent to keep compatibility.
- *
- *     Locking: Caller should hold termios lock. This is already held
- *     when calling this function from the driver termios handler.
- *
- *     The ifdefs deal with platforms whose owners have yet to update them
- *     and will all go away once this is done.
- */
-
-void tty_termios_encode_baud_rate(struct ktermios *termios,
-                                 speed_t ibaud, speed_t obaud)
-{
-       int i = 0;
-       int ifound = -1, ofound = -1;
-       int iclose = ibaud/50, oclose = obaud/50;
-       int ibinput = 0;
-
-       if (obaud == 0)                 /* CD dropped             */
-               ibaud = 0;              /* Clear ibaud to be sure */
-
-       termios->c_ispeed = ibaud;
-       termios->c_ospeed = obaud;
-
-#ifdef BOTHER
-       /* If the user asked for a precise weird speed give a precise weird
-          answer. If they asked for a Bfoo speed they many have problems
-          digesting non-exact replies so fuzz a bit */
-
-       if ((termios->c_cflag & CBAUD) == BOTHER)
-               oclose = 0;
-       if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
-               iclose = 0;
-       if ((termios->c_cflag >> IBSHIFT) & CBAUD)
-               ibinput = 1;    /* An input speed was specified */
-#endif
-       termios->c_cflag &= ~CBAUD;
-
-       /*
-        *      Our goal is to find a close match to the standard baud rate
-        *      returned. Walk the baud rate table and if we get a very close
-        *      match then report back the speed as a POSIX Bxxxx value by
-        *      preference
-        */
-
-       do {
-               if (obaud - oclose <= baud_table[i] &&
-                   obaud + oclose >= baud_table[i]) {
-                       termios->c_cflag |= baud_bits[i];
-                       ofound = i;
-               }
-               if (ibaud - iclose <= baud_table[i] &&
-                   ibaud + iclose >= baud_table[i]) {
-                       /* For the case input == output don't set IBAUD bits
-                          if the user didn't do so */
-                       if (ofound == i && !ibinput)
-                               ifound  = i;
-#ifdef IBSHIFT
-                       else {
-                               ifound = i;
-                               termios->c_cflag |= (baud_bits[i] << IBSHIFT);
-                       }
-#endif
-               }
-       } while (++i < n_baud_table);
-
-       /*
-        *      If we found no match then use BOTHER if provided or warn
-        *      the user their platform maintainer needs to wake up if not.
-        */
-#ifdef BOTHER
-       if (ofound == -1)
-               termios->c_cflag |= BOTHER;
-       /* Set exact input bits only if the input and output differ or the
-          user already did */
-       if (ifound == -1 && (ibaud != obaud || ibinput))
-               termios->c_cflag |= (BOTHER << IBSHIFT);
-#else
-       if (ifound == -1 || ofound == -1) {
-               printk_once(KERN_WARNING "tty: Unable to return correct "
-                         "speed data as your architecture needs updating.\n");
-       }
-#endif
-}
-EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
-
-/**
- *     tty_encode_baud_rate            -       set baud rate of the tty
- *     @ibaud: input baud rate
- *     @obad: output baud rate
- *
- *     Update the current termios data for the tty with the new speed
- *     settings. The caller must hold the termios_mutex for the tty in
- *     question.
- */
-
-void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
-{
-       tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
-}
-EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
-
-/**
- *     tty_get_baud_rate       -       get tty bit rates
- *     @tty: tty to query
- *
- *     Returns the baud rate as an integer for this terminal. The
- *     termios lock must be held by the caller and the terminal bit
- *     flags may be updated.
- *
- *     Locking: none
- */
-
-speed_t tty_get_baud_rate(struct tty_struct *tty)
-{
-       speed_t baud = tty_termios_baud_rate(tty->termios);
-
-       if (baud == 38400 && tty->alt_speed) {
-               if (!tty->warned) {
-                       printk(KERN_WARNING "Use of setserial/setrocket to "
-                                           "set SPD_* flags is deprecated\n");
-                       tty->warned = 1;
-               }
-               baud = tty->alt_speed;
-       }
-
-       return baud;
-}
-EXPORT_SYMBOL(tty_get_baud_rate);
-
-/**
- *     tty_termios_copy_hw     -       copy hardware settings
- *     @new: New termios
- *     @old: Old termios
- *
- *     Propogate the hardware specific terminal setting bits from
- *     the old termios structure to the new one. This is used in cases
- *     where the hardware does not support reconfiguration or as a helper
- *     in some cases where only minimal reconfiguration is supported
- */
-
-void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
-{
-       /* The bits a dumb device handles in software. Smart devices need
-          to always provide a set_termios method */
-       new->c_cflag &= HUPCL | CREAD | CLOCAL;
-       new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
-       new->c_ispeed = old->c_ispeed;
-       new->c_ospeed = old->c_ospeed;
-}
-EXPORT_SYMBOL(tty_termios_copy_hw);
-
-/**
- *     tty_termios_hw_change   -       check for setting change
- *     @a: termios
- *     @b: termios to compare
- *
- *     Check if any of the bits that affect a dumb device have changed
- *     between the two termios structures, or a speed change is needed.
- */
-
-int tty_termios_hw_change(struct ktermios *a, struct ktermios *b)
-{
-       if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
-               return 1;
-       if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
-               return 1;
-       return 0;
-}
-EXPORT_SYMBOL(tty_termios_hw_change);
-
-/**
- *     change_termios          -       update termios values
- *     @tty: tty to update
- *     @new_termios: desired new value
- *
- *     Perform updates to the termios values set on this terminal. There
- *     is a bit of layering violation here with n_tty in terms of the
- *     internal knowledge of this function.
- *
- *     Locking: termios_mutex
- */
-
-static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
-{
-       struct ktermios old_termios;
-       struct tty_ldisc *ld;
-       unsigned long flags;
-
-       /*
-        *      Perform the actual termios internal changes under lock.
-        */
-
-
-       /* FIXME: we need to decide on some locking/ordering semantics
-          for the set_termios notification eventually */
-       mutex_lock(&tty->termios_mutex);
-       old_termios = *tty->termios;
-       *tty->termios = *new_termios;
-       unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
-
-       /* See if packet mode change of state. */
-       if (tty->link && tty->link->packet) {
-               int extproc = (old_termios.c_lflag & EXTPROC) |
-                               (tty->termios->c_lflag & EXTPROC);
-               int old_flow = ((old_termios.c_iflag & IXON) &&
-                               (old_termios.c_cc[VSTOP] == '\023') &&
-                               (old_termios.c_cc[VSTART] == '\021'));
-               int new_flow = (I_IXON(tty) &&
-                               STOP_CHAR(tty) == '\023' &&
-                               START_CHAR(tty) == '\021');
-               if ((old_flow != new_flow) || extproc) {
-                       spin_lock_irqsave(&tty->ctrl_lock, flags);
-                       if (old_flow != new_flow) {
-                               tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
-                               if (new_flow)
-                                       tty->ctrl_status |= TIOCPKT_DOSTOP;
-                               else
-                                       tty->ctrl_status |= TIOCPKT_NOSTOP;
-                       }
-                       if (extproc)
-                               tty->ctrl_status |= TIOCPKT_IOCTL;
-                       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-                       wake_up_interruptible(&tty->link->read_wait);
-               }
-       }
-
-       if (tty->ops->set_termios)
-               (*tty->ops->set_termios)(tty, &old_termios);
-       else
-               tty_termios_copy_hw(tty->termios, &old_termios);
-
-       ld = tty_ldisc_ref(tty);
-       if (ld != NULL) {
-               if (ld->ops->set_termios)
-                       (ld->ops->set_termios)(tty, &old_termios);
-               tty_ldisc_deref(ld);
-       }
-       mutex_unlock(&tty->termios_mutex);
-}
-
-/**
- *     set_termios             -       set termios values for a tty
- *     @tty: terminal device
- *     @arg: user data
- *     @opt: option information
- *
- *     Helper function to prepare termios data and run necessary other
- *     functions before using change_termios to do the actual changes.
- *
- *     Locking:
- *             Called functions take ldisc and termios_mutex locks
- */
-
-static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
-{
-       struct ktermios tmp_termios;
-       struct tty_ldisc *ld;
-       int retval = tty_check_change(tty);
-
-       if (retval)
-               return retval;
-
-       mutex_lock(&tty->termios_mutex);
-       memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
-       mutex_unlock(&tty->termios_mutex);
-
-       if (opt & TERMIOS_TERMIO) {
-               if (user_termio_to_kernel_termios(&tmp_termios,
-                                               (struct termio __user *)arg))
-                       return -EFAULT;
-#ifdef TCGETS2
-       } else if (opt & TERMIOS_OLD) {
-               if (user_termios_to_kernel_termios_1(&tmp_termios,
-                                               (struct termios __user *)arg))
-                       return -EFAULT;
-       } else {
-               if (user_termios_to_kernel_termios(&tmp_termios,
-                                               (struct termios2 __user *)arg))
-                       return -EFAULT;
-       }
-#else
-       } else if (user_termios_to_kernel_termios(&tmp_termios,
-                                       (struct termios __user *)arg))
-               return -EFAULT;
-#endif
-
-       /* If old style Bfoo values are used then load c_ispeed/c_ospeed
-        * with the real speed so its unconditionally usable */
-       tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
-       tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
-
-       ld = tty_ldisc_ref(tty);
-
-       if (ld != NULL) {
-               if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               tty_ldisc_deref(ld);
-       }
-
-       if (opt & TERMIOS_WAIT) {
-               tty_wait_until_sent(tty, 0);
-               if (signal_pending(current))
-                       return -EINTR;
-       }
-
-       change_termios(tty, &tmp_termios);
-
-       /* FIXME: Arguably if tmp_termios == tty->termios AND the
-          actual requested termios was not tmp_termios then we may
-          want to return an error as no user requested change has
-          succeeded */
-       return 0;
-}
-
-static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
-{
-       mutex_lock(&tty->termios_mutex);
-       memcpy(kterm, tty->termios, sizeof(struct ktermios));
-       mutex_unlock(&tty->termios_mutex);
-}
-
-static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
-{
-       mutex_lock(&tty->termios_mutex);
-       memcpy(kterm, tty->termios_locked, sizeof(struct ktermios));
-       mutex_unlock(&tty->termios_mutex);
-}
-
-static int get_termio(struct tty_struct *tty, struct termio __user *termio)
-{
-       struct ktermios kterm;
-       copy_termios(tty, &kterm);
-       if (kernel_termios_to_user_termio(termio, &kterm))
-               return -EFAULT;
-       return 0;
-}
-
-
-#ifdef TCGETX
-
-/**
- *     set_termiox     -       set termiox fields if possible
- *     @tty: terminal
- *     @arg: termiox structure from user
- *     @opt: option flags for ioctl type
- *
- *     Implement the device calling points for the SYS5 termiox ioctl
- *     interface in Linux
- */
-
-static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
-{
-       struct termiox tnew;
-       struct tty_ldisc *ld;
-
-       if (tty->termiox == NULL)
-               return -EINVAL;
-       if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
-               return -EFAULT;
-
-       ld = tty_ldisc_ref(tty);
-       if (ld != NULL) {
-               if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               tty_ldisc_deref(ld);
-       }
-       if (opt & TERMIOS_WAIT) {
-               tty_wait_until_sent(tty, 0);
-               if (signal_pending(current))
-                       return -EINTR;
-       }
-
-       mutex_lock(&tty->termios_mutex);
-       if (tty->ops->set_termiox)
-               tty->ops->set_termiox(tty, &tnew);
-       mutex_unlock(&tty->termios_mutex);
-       return 0;
-}
-
-#endif
-
-
-#ifdef TIOCGETP
-/*
- * These are deprecated, but there is limited support..
- *
- * The "sg_flags" translation is a joke..
- */
-static int get_sgflags(struct tty_struct *tty)
-{
-       int flags = 0;
-
-       if (!(tty->termios->c_lflag & ICANON)) {
-               if (tty->termios->c_lflag & ISIG)
-                       flags |= 0x02;          /* cbreak */
-               else
-                       flags |= 0x20;          /* raw */
-       }
-       if (tty->termios->c_lflag & ECHO)
-               flags |= 0x08;                  /* echo */
-       if (tty->termios->c_oflag & OPOST)
-               if (tty->termios->c_oflag & ONLCR)
-                       flags |= 0x10;          /* crmod */
-       return flags;
-}
-
-static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
-{
-       struct sgttyb tmp;
-
-       mutex_lock(&tty->termios_mutex);
-       tmp.sg_ispeed = tty->termios->c_ispeed;
-       tmp.sg_ospeed = tty->termios->c_ospeed;
-       tmp.sg_erase = tty->termios->c_cc[VERASE];
-       tmp.sg_kill = tty->termios->c_cc[VKILL];
-       tmp.sg_flags = get_sgflags(tty);
-       mutex_unlock(&tty->termios_mutex);
-
-       return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
-}
-
-static void set_sgflags(struct ktermios *termios, int flags)
-{
-       termios->c_iflag = ICRNL | IXON;
-       termios->c_oflag = 0;
-       termios->c_lflag = ISIG | ICANON;
-       if (flags & 0x02) {     /* cbreak */
-               termios->c_iflag = 0;
-               termios->c_lflag &= ~ICANON;
-       }
-       if (flags & 0x08) {             /* echo */
-               termios->c_lflag |= ECHO | ECHOE | ECHOK |
-                                   ECHOCTL | ECHOKE | IEXTEN;
-       }
-       if (flags & 0x10) {             /* crmod */
-               termios->c_oflag |= OPOST | ONLCR;
-       }
-       if (flags & 0x20) {     /* raw */
-               termios->c_iflag = 0;
-               termios->c_lflag &= ~(ISIG | ICANON);
-       }
-       if (!(termios->c_lflag & ICANON)) {
-               termios->c_cc[VMIN] = 1;
-               termios->c_cc[VTIME] = 0;
-       }
-}
-
-/**
- *     set_sgttyb              -       set legacy terminal values
- *     @tty: tty structure
- *     @sgttyb: pointer to old style terminal structure
- *
- *     Updates a terminal from the legacy BSD style terminal information
- *     structure.
- *
- *     Locking: termios_mutex
- */
-
-static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
-{
-       int retval;
-       struct sgttyb tmp;
-       struct ktermios termios;
-
-       retval = tty_check_change(tty);
-       if (retval)
-               return retval;
-
-       if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
-               return -EFAULT;
-
-       mutex_lock(&tty->termios_mutex);
-       termios = *tty->termios;
-       termios.c_cc[VERASE] = tmp.sg_erase;
-       termios.c_cc[VKILL] = tmp.sg_kill;
-       set_sgflags(&termios, tmp.sg_flags);
-       /* Try and encode into Bfoo format */
-#ifdef BOTHER
-       tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
-                                               termios.c_ospeed);
-#endif
-       mutex_unlock(&tty->termios_mutex);
-       change_termios(tty, &termios);
-       return 0;
-}
-#endif
-
-#ifdef TIOCGETC
-static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
-{
-       struct tchars tmp;
-
-       mutex_lock(&tty->termios_mutex);
-       tmp.t_intrc = tty->termios->c_cc[VINTR];
-       tmp.t_quitc = tty->termios->c_cc[VQUIT];
-       tmp.t_startc = tty->termios->c_cc[VSTART];
-       tmp.t_stopc = tty->termios->c_cc[VSTOP];
-       tmp.t_eofc = tty->termios->c_cc[VEOF];
-       tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
-       mutex_unlock(&tty->termios_mutex);
-       return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
-}
-
-static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
-{
-       struct tchars tmp;
-
-       if (copy_from_user(&tmp, tchars, sizeof(tmp)))
-               return -EFAULT;
-       mutex_lock(&tty->termios_mutex);
-       tty->termios->c_cc[VINTR] = tmp.t_intrc;
-       tty->termios->c_cc[VQUIT] = tmp.t_quitc;
-       tty->termios->c_cc[VSTART] = tmp.t_startc;
-       tty->termios->c_cc[VSTOP] = tmp.t_stopc;
-       tty->termios->c_cc[VEOF] = tmp.t_eofc;
-       tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
-       mutex_unlock(&tty->termios_mutex);
-       return 0;
-}
-#endif
-
-#ifdef TIOCGLTC
-static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
-{
-       struct ltchars tmp;
-
-       mutex_lock(&tty->termios_mutex);
-       tmp.t_suspc = tty->termios->c_cc[VSUSP];
-       /* what is dsuspc anyway? */
-       tmp.t_dsuspc = tty->termios->c_cc[VSUSP];
-       tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
-       /* what is flushc anyway? */
-       tmp.t_flushc = tty->termios->c_cc[VEOL2];
-       tmp.t_werasc = tty->termios->c_cc[VWERASE];
-       tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
-       mutex_unlock(&tty->termios_mutex);
-       return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
-}
-
-static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
-{
-       struct ltchars tmp;
-
-       if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
-               return -EFAULT;
-
-       mutex_lock(&tty->termios_mutex);
-       tty->termios->c_cc[VSUSP] = tmp.t_suspc;
-       /* what is dsuspc anyway? */
-       tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;
-       tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
-       /* what is flushc anyway? */
-       tty->termios->c_cc[VEOL2] = tmp.t_flushc;
-       tty->termios->c_cc[VWERASE] = tmp.t_werasc;
-       tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
-       mutex_unlock(&tty->termios_mutex);
-       return 0;
-}
-#endif
-
-/**
- *     send_prio_char          -       send priority character
- *
- *     Send a high priority character to the tty even if stopped
- *
- *     Locking: none for xchar method, write ordering for write method.
- */
-
-static int send_prio_char(struct tty_struct *tty, char ch)
-{
-       int     was_stopped = tty->stopped;
-
-       if (tty->ops->send_xchar) {
-               tty->ops->send_xchar(tty, ch);
-               return 0;
-       }
-
-       if (tty_write_lock(tty, 0) < 0)
-               return -ERESTARTSYS;
-
-       if (was_stopped)
-               start_tty(tty);
-       tty->ops->write(tty, &ch, 1);
-       if (was_stopped)
-               stop_tty(tty);
-       tty_write_unlock(tty);
-       return 0;
-}
-
-/**
- *     tty_change_softcar      -       carrier change ioctl helper
- *     @tty: tty to update
- *     @arg: enable/disable CLOCAL
- *
- *     Perform a change to the CLOCAL state and call into the driver
- *     layer to make it visible. All done with the termios mutex
- */
-
-static int tty_change_softcar(struct tty_struct *tty, int arg)
-{
-       int ret = 0;
-       int bit = arg ? CLOCAL : 0;
-       struct ktermios old;
-
-       mutex_lock(&tty->termios_mutex);
-       old = *tty->termios;
-       tty->termios->c_cflag &= ~CLOCAL;
-       tty->termios->c_cflag |= bit;
-       if (tty->ops->set_termios)
-               tty->ops->set_termios(tty, &old);
-       if ((tty->termios->c_cflag & CLOCAL) != bit)
-               ret = -EINVAL;
-       mutex_unlock(&tty->termios_mutex);
-       return ret;
-}
-
-/**
- *     tty_mode_ioctl          -       mode related ioctls
- *     @tty: tty for the ioctl
- *     @file: file pointer for the tty
- *     @cmd: command
- *     @arg: ioctl argument
- *
- *     Perform non line discipline specific mode control ioctls. This
- *     is designed to be called by line disciplines to ensure they provide
- *     consistent mode setting.
- */
-
-int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
-                       unsigned int cmd, unsigned long arg)
-{
-       struct tty_struct *real_tty;
-       void __user *p = (void __user *)arg;
-       int ret = 0;
-       struct ktermios kterm;
-
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-           tty->driver->subtype == PTY_TYPE_MASTER)
-               real_tty = tty->link;
-       else
-               real_tty = tty;
-
-       switch (cmd) {
-#ifdef TIOCGETP
-       case TIOCGETP:
-               return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
-       case TIOCSETP:
-       case TIOCSETN:
-               return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
-#endif
-#ifdef TIOCGETC
-       case TIOCGETC:
-               return get_tchars(real_tty, p);
-       case TIOCSETC:
-               return set_tchars(real_tty, p);
-#endif
-#ifdef TIOCGLTC
-       case TIOCGLTC:
-               return get_ltchars(real_tty, p);
-       case TIOCSLTC:
-               return set_ltchars(real_tty, p);
-#endif
-       case TCSETSF:
-               return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
-       case TCSETSW:
-               return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
-       case TCSETS:
-               return set_termios(real_tty, p, TERMIOS_OLD);
-#ifndef TCGETS2
-       case TCGETS:
-               copy_termios(real_tty, &kterm);
-               if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
-                       ret = -EFAULT;
-               return ret;
-#else
-       case TCGETS:
-               copy_termios(real_tty, &kterm);
-               if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
-                       ret = -EFAULT;
-               return ret;
-       case TCGETS2:
-               copy_termios(real_tty, &kterm);
-               if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
-                       ret = -EFAULT;
-               return ret;
-       case TCSETSF2:
-               return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);
-       case TCSETSW2:
-               return set_termios(real_tty, p, TERMIOS_WAIT);
-       case TCSETS2:
-               return set_termios(real_tty, p, 0);
-#endif
-       case TCGETA:
-               return get_termio(real_tty, p);
-       case TCSETAF:
-               return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
-       case TCSETAW:
-               return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
-       case TCSETA:
-               return set_termios(real_tty, p, TERMIOS_TERMIO);
-#ifndef TCGETS2
-       case TIOCGLCKTRMIOS:
-               copy_termios_locked(real_tty, &kterm);
-               if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
-                       ret = -EFAULT;
-               return ret;
-       case TIOCSLCKTRMIOS:
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               copy_termios_locked(real_tty, &kterm);
-               if (user_termios_to_kernel_termios(&kterm,
-                                              (struct termios __user *) arg))
-                       return -EFAULT;
-               mutex_lock(&real_tty->termios_mutex);
-               memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
-               mutex_unlock(&real_tty->termios_mutex);
-               return 0;
-#else
-       case TIOCGLCKTRMIOS:
-               copy_termios_locked(real_tty, &kterm);
-               if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
-                       ret = -EFAULT;
-               return ret;
-       case TIOCSLCKTRMIOS:
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               copy_termios_locked(real_tty, &kterm);
-               if (user_termios_to_kernel_termios_1(&kterm,
-                                              (struct termios __user *) arg))
-                       return -EFAULT;
-               mutex_lock(&real_tty->termios_mutex);
-               memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
-               mutex_unlock(&real_tty->termios_mutex);
-               return ret;
-#endif
-#ifdef TCGETX
-       case TCGETX: {
-               struct termiox ktermx;
-               if (real_tty->termiox == NULL)
-                       return -EINVAL;
-               mutex_lock(&real_tty->termios_mutex);
-               memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
-               mutex_unlock(&real_tty->termios_mutex);
-               if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
-                       ret = -EFAULT;
-               return ret;
-       }
-       case TCSETX:
-               return set_termiox(real_tty, p, 0);
-       case TCSETXW:
-               return set_termiox(real_tty, p, TERMIOS_WAIT);
-       case TCSETXF:
-               return set_termiox(real_tty, p, TERMIOS_FLUSH);
-#endif         
-       case TIOCGSOFTCAR:
-               copy_termios(real_tty, &kterm);
-               ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
-                                               (int __user *)arg);
-               return ret;
-       case TIOCSSOFTCAR:
-               if (get_user(arg, (unsigned int __user *) arg))
-                       return -EFAULT;
-               return tty_change_softcar(real_tty, arg);
-       default:
-               return -ENOIOCTLCMD;
-       }
-}
-EXPORT_SYMBOL_GPL(tty_mode_ioctl);
-
-int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
-{
-       struct tty_ldisc *ld;
-       int retval = tty_check_change(tty);
-       if (retval)
-               return retval;
-
-       ld = tty_ldisc_ref_wait(tty);
-       switch (arg) {
-       case TCIFLUSH:
-               if (ld && ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               break;
-       case TCIOFLUSH:
-               if (ld && ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               /* fall through */
-       case TCOFLUSH:
-               tty_driver_flush_buffer(tty);
-               break;
-       default:
-               tty_ldisc_deref(ld);
-               return -EINVAL;
-       }
-       tty_ldisc_deref(ld);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(tty_perform_flush);
-
-int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       unsigned long flags;
-       int retval;
-
-       switch (cmd) {
-       case TCXONC:
-               retval = tty_check_change(tty);
-               if (retval)
-                       return retval;
-               switch (arg) {
-               case TCOOFF:
-                       if (!tty->flow_stopped) {
-                               tty->flow_stopped = 1;
-                               stop_tty(tty);
-                       }
-                       break;
-               case TCOON:
-                       if (tty->flow_stopped) {
-                               tty->flow_stopped = 0;
-                               start_tty(tty);
-                       }
-                       break;
-               case TCIOFF:
-                       if (STOP_CHAR(tty) != __DISABLED_CHAR)
-                               return send_prio_char(tty, STOP_CHAR(tty));
-                       break;
-               case TCION:
-                       if (START_CHAR(tty) != __DISABLED_CHAR)
-                               return send_prio_char(tty, START_CHAR(tty));
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               return 0;
-       case TCFLSH:
-               return tty_perform_flush(tty, arg);
-       case TIOCPKT:
-       {
-               int pktmode;
-
-               if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
-                   tty->driver->subtype != PTY_TYPE_MASTER)
-                       return -ENOTTY;
-               if (get_user(pktmode, (int __user *) arg))
-                       return -EFAULT;
-               spin_lock_irqsave(&tty->ctrl_lock, flags);
-               if (pktmode) {
-                       if (!tty->packet) {
-                               tty->packet = 1;
-                               tty->link->ctrl_status = 0;
-                       }
-               } else
-                       tty->packet = 0;
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               return 0;
-       }
-       default:
-               /* Try the mode commands */
-               return tty_mode_ioctl(tty, file, cmd, arg);
-       }
-}
-EXPORT_SYMBOL(n_tty_ioctl_helper);
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
deleted file mode 100644 (file)
index 412f977..0000000
+++ /dev/null
@@ -1,915 +0,0 @@
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/devpts_fs.h>
-#include <linux/file.h>
-#include <linux/console.h>
-#include <linux/timer.h>
-#include <linux/ctype.h>
-#include <linux/kd.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/proc_fs.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/seq_file.h>
-
-#include <linux/uaccess.h>
-#include <asm/system.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-
-#include <linux/smp_lock.h>    /* For the moment */
-
-#include <linux/kmod.h>
-#include <linux/nsproxy.h>
-
-/*
- *     This guards the refcounted line discipline lists. The lock
- *     must be taken with irqs off because there are hangup path
- *     callers who will do ldisc lookups and cannot sleep.
- */
-
-static DEFINE_SPINLOCK(tty_ldisc_lock);
-static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
-/* Line disc dispatch table */
-static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
-
-static inline struct tty_ldisc *get_ldisc(struct tty_ldisc *ld)
-{
-       if (ld)
-               atomic_inc(&ld->users);
-       return ld;
-}
-
-static void put_ldisc(struct tty_ldisc *ld)
-{
-       unsigned long flags;
-
-       if (WARN_ON_ONCE(!ld))
-               return;
-
-       /*
-        * If this is the last user, free the ldisc, and
-        * release the ldisc ops.
-        *
-        * We really want an "atomic_dec_and_lock_irqsave()",
-        * but we don't have it, so this does it by hand.
-        */
-       local_irq_save(flags);
-       if (atomic_dec_and_lock(&ld->users, &tty_ldisc_lock)) {
-               struct tty_ldisc_ops *ldo = ld->ops;
-
-               ldo->refcount--;
-               module_put(ldo->owner);
-               spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
-               kfree(ld);
-               return;
-       }
-       local_irq_restore(flags);
-}
-
-/**
- *     tty_register_ldisc      -       install a line discipline
- *     @disc: ldisc number
- *     @new_ldisc: pointer to the ldisc object
- *
- *     Installs a new line discipline into the kernel. The discipline
- *     is set up as unreferenced and then made available to the kernel
- *     from this point onwards.
- *
- *     Locking:
- *             takes tty_ldisc_lock to guard against ldisc races
- */
-
-int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
-{
-       unsigned long flags;
-       int ret = 0;
-
-       if (disc < N_TTY || disc >= NR_LDISCS)
-               return -EINVAL;
-
-       spin_lock_irqsave(&tty_ldisc_lock, flags);
-       tty_ldiscs[disc] = new_ldisc;
-       new_ldisc->num = disc;
-       new_ldisc->refcount = 0;
-       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
-       return ret;
-}
-EXPORT_SYMBOL(tty_register_ldisc);
-
-/**
- *     tty_unregister_ldisc    -       unload a line discipline
- *     @disc: ldisc number
- *     @new_ldisc: pointer to the ldisc object
- *
- *     Remove a line discipline from the kernel providing it is not
- *     currently in use.
- *
- *     Locking:
- *             takes tty_ldisc_lock to guard against ldisc races
- */
-
-int tty_unregister_ldisc(int disc)
-{
-       unsigned long flags;
-       int ret = 0;
-
-       if (disc < N_TTY || disc >= NR_LDISCS)
-               return -EINVAL;
-
-       spin_lock_irqsave(&tty_ldisc_lock, flags);
-       if (tty_ldiscs[disc]->refcount)
-               ret = -EBUSY;
-       else
-               tty_ldiscs[disc] = NULL;
-       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-
-       return ret;
-}
-EXPORT_SYMBOL(tty_unregister_ldisc);
-
-static struct tty_ldisc_ops *get_ldops(int disc)
-{
-       unsigned long flags;
-       struct tty_ldisc_ops *ldops, *ret;
-
-       spin_lock_irqsave(&tty_ldisc_lock, flags);
-       ret = ERR_PTR(-EINVAL);
-       ldops = tty_ldiscs[disc];
-       if (ldops) {
-               ret = ERR_PTR(-EAGAIN);
-               if (try_module_get(ldops->owner)) {
-                       ldops->refcount++;
-                       ret = ldops;
-               }
-       }
-       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-       return ret;
-}
-
-static void put_ldops(struct tty_ldisc_ops *ldops)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&tty_ldisc_lock, flags);
-       ldops->refcount--;
-       module_put(ldops->owner);
-       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-}
-
-/**
- *     tty_ldisc_get           -       take a reference to an ldisc
- *     @disc: ldisc number
- *
- *     Takes a reference to a line discipline. Deals with refcounts and
- *     module locking counts. Returns NULL if the discipline is not available.
- *     Returns a pointer to the discipline and bumps the ref count if it is
- *     available
- *
- *     Locking:
- *             takes tty_ldisc_lock to guard against ldisc races
- */
-
-static struct tty_ldisc *tty_ldisc_get(int disc)
-{
-       struct tty_ldisc *ld;
-       struct tty_ldisc_ops *ldops;
-
-       if (disc < N_TTY || disc >= NR_LDISCS)
-               return ERR_PTR(-EINVAL);
-
-       /*
-        * Get the ldisc ops - we may need to request them to be loaded
-        * dynamically and try again.
-        */
-       ldops = get_ldops(disc);
-       if (IS_ERR(ldops)) {
-               request_module("tty-ldisc-%d", disc);
-               ldops = get_ldops(disc);
-               if (IS_ERR(ldops))
-                       return ERR_CAST(ldops);
-       }
-
-       ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
-       if (ld == NULL) {
-               put_ldops(ldops);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       ld->ops = ldops;
-       atomic_set(&ld->users, 1);
-       return ld;
-}
-
-static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
-{
-       return (*pos < NR_LDISCS) ? pos : NULL;
-}
-
-static void *tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
-{
-       (*pos)++;
-       return (*pos < NR_LDISCS) ? pos : NULL;
-}
-
-static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
-{
-}
-
-static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
-{
-       int i = *(loff_t *)v;
-       struct tty_ldisc_ops *ldops;
-
-       ldops = get_ldops(i);
-       if (IS_ERR(ldops))
-               return 0;
-       seq_printf(m, "%-10s %2d\n", ldops->name ? ldops->name : "???", i);
-       put_ldops(ldops);
-       return 0;
-}
-
-static const struct seq_operations tty_ldiscs_seq_ops = {
-       .start  = tty_ldiscs_seq_start,
-       .next   = tty_ldiscs_seq_next,
-       .stop   = tty_ldiscs_seq_stop,
-       .show   = tty_ldiscs_seq_show,
-};
-
-static int proc_tty_ldiscs_open(struct inode *inode, struct file *file)
-{
-       return seq_open(file, &tty_ldiscs_seq_ops);
-}
-
-const struct file_operations tty_ldiscs_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = proc_tty_ldiscs_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release,
-};
-
-/**
- *     tty_ldisc_assign        -       set ldisc on a tty
- *     @tty: tty to assign
- *     @ld: line discipline
- *
- *     Install an instance of a line discipline into a tty structure. The
- *     ldisc must have a reference count above zero to ensure it remains.
- *     The tty instance refcount starts at zero.
- *
- *     Locking:
- *             Caller must hold references
- */
-
-static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
-{
-       tty->ldisc = ld;
-}
-
-/**
- *     tty_ldisc_try           -       internal helper
- *     @tty: the tty
- *
- *     Make a single attempt to grab and bump the refcount on
- *     the tty ldisc. Return 0 on failure or 1 on success. This is
- *     used to implement both the waiting and non waiting versions
- *     of tty_ldisc_ref
- *
- *     Locking: takes tty_ldisc_lock
- */
-
-static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
-{
-       unsigned long flags;
-       struct tty_ldisc *ld;
-
-       spin_lock_irqsave(&tty_ldisc_lock, flags);
-       ld = NULL;
-       if (test_bit(TTY_LDISC, &tty->flags))
-               ld = get_ldisc(tty->ldisc);
-       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-       return ld;
-}
-
-/**
- *     tty_ldisc_ref_wait      -       wait for the tty ldisc
- *     @tty: tty device
- *
- *     Dereference the line discipline for the terminal and take a
- *     reference to it. If the line discipline is in flux then
- *     wait patiently until it changes.
- *
- *     Note: Must not be called from an IRQ/timer context. The caller
- *     must also be careful not to hold other locks that will deadlock
- *     against a discipline change, such as an existing ldisc reference
- *     (which we check for)
- *
- *     Locking: call functions take tty_ldisc_lock
- */
-
-struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
-{
-       struct tty_ldisc *ld;
-
-       /* wait_event is a macro */
-       wait_event(tty_ldisc_wait, (ld = tty_ldisc_try(tty)) != NULL);
-       return ld;
-}
-EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
-
-/**
- *     tty_ldisc_ref           -       get the tty ldisc
- *     @tty: tty device
- *
- *     Dereference the line discipline for the terminal and take a
- *     reference to it. If the line discipline is in flux then
- *     return NULL. Can be called from IRQ and timer functions.
- *
- *     Locking: called functions take tty_ldisc_lock
- */
-
-struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
-{
-       return tty_ldisc_try(tty);
-}
-EXPORT_SYMBOL_GPL(tty_ldisc_ref);
-
-/**
- *     tty_ldisc_deref         -       free a tty ldisc reference
- *     @ld: reference to free up
- *
- *     Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May
- *     be called in IRQ context.
- *
- *     Locking: takes tty_ldisc_lock
- */
-
-void tty_ldisc_deref(struct tty_ldisc *ld)
-{
-       put_ldisc(ld);
-}
-EXPORT_SYMBOL_GPL(tty_ldisc_deref);
-
-static inline void tty_ldisc_put(struct tty_ldisc *ld)
-{
-       put_ldisc(ld);
-}
-
-/**
- *     tty_ldisc_enable        -       allow ldisc use
- *     @tty: terminal to activate ldisc on
- *
- *     Set the TTY_LDISC flag when the line discipline can be called
- *     again. Do necessary wakeups for existing sleepers. Clear the LDISC
- *     changing flag to indicate any ldisc change is now over.
- *
- *     Note: nobody should set the TTY_LDISC bit except via this function.
- *     Clearing directly is allowed.
- */
-
-void tty_ldisc_enable(struct tty_struct *tty)
-{
-       set_bit(TTY_LDISC, &tty->flags);
-       clear_bit(TTY_LDISC_CHANGING, &tty->flags);
-       wake_up(&tty_ldisc_wait);
-}
-
-/**
- *     tty_ldisc_flush -       flush line discipline queue
- *     @tty: tty
- *
- *     Flush the line discipline queue (if any) for this tty. If there
- *     is no line discipline active this is a no-op.
- */
-
-void tty_ldisc_flush(struct tty_struct *tty)
-{
-       struct tty_ldisc *ld = tty_ldisc_ref(tty);
-       if (ld) {
-               if (ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               tty_ldisc_deref(ld);
-       }
-       tty_buffer_flush(tty);
-}
-EXPORT_SYMBOL_GPL(tty_ldisc_flush);
-
-/**
- *     tty_set_termios_ldisc           -       set ldisc field
- *     @tty: tty structure
- *     @num: line discipline number
- *
- *     This is probably overkill for real world processors but
- *     they are not on hot paths so a little discipline won't do
- *     any harm.
- *
- *     Locking: takes termios_mutex
- */
-
-static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
-{
-       mutex_lock(&tty->termios_mutex);
-       tty->termios->c_line = num;
-       mutex_unlock(&tty->termios_mutex);
-}
-
-/**
- *     tty_ldisc_open          -       open a line discipline
- *     @tty: tty we are opening the ldisc on
- *     @ld: discipline to open
- *
- *     A helper opening method. Also a convenient debugging and check
- *     point.
- *
- *     Locking: always called with BTM already held.
- */
-
-static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
-{
-       WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
-       if (ld->ops->open) {
-               int ret;
-                /* BTM here locks versus a hangup event */
-               WARN_ON(!tty_locked());
-               ret = ld->ops->open(tty);
-               return ret;
-       }
-       return 0;
-}
-
-/**
- *     tty_ldisc_close         -       close a line discipline
- *     @tty: tty we are opening the ldisc on
- *     @ld: discipline to close
- *
- *     A helper close method. Also a convenient debugging and check
- *     point.
- */
-
-static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
-{
-       WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags));
-       clear_bit(TTY_LDISC_OPEN, &tty->flags);
-       if (ld->ops->close)
-               ld->ops->close(tty);
-}
-
-/**
- *     tty_ldisc_restore       -       helper for tty ldisc change
- *     @tty: tty to recover
- *     @old: previous ldisc
- *
- *     Restore the previous line discipline or N_TTY when a line discipline
- *     change fails due to an open error
- */
-
-static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
-{
-       char buf[64];
-       struct tty_ldisc *new_ldisc;
-       int r;
-
-       /* There is an outstanding reference here so this is safe */
-       old = tty_ldisc_get(old->ops->num);
-       WARN_ON(IS_ERR(old));
-       tty_ldisc_assign(tty, old);
-       tty_set_termios_ldisc(tty, old->ops->num);
-       if (tty_ldisc_open(tty, old) < 0) {
-               tty_ldisc_put(old);
-               /* This driver is always present */
-               new_ldisc = tty_ldisc_get(N_TTY);
-               if (IS_ERR(new_ldisc))
-                       panic("n_tty: get");
-               tty_ldisc_assign(tty, new_ldisc);
-               tty_set_termios_ldisc(tty, N_TTY);
-               r = tty_ldisc_open(tty, new_ldisc);
-               if (r < 0)
-                       panic("Couldn't open N_TTY ldisc for "
-                             "%s --- error %d.",
-                             tty_name(tty, buf), r);
-       }
-}
-
-/**
- *     tty_ldisc_halt          -       shut down the line discipline
- *     @tty: tty device
- *
- *     Shut down the line discipline and work queue for this tty device.
- *     The TTY_LDISC flag being cleared ensures no further references can
- *     be obtained while the delayed work queue halt ensures that no more
- *     data is fed to the ldisc.
- *
- *     You need to do a 'flush_scheduled_work()' (outside the ldisc_mutex)
- *     in order to make sure any currently executing ldisc work is also
- *     flushed.
- */
-
-static int tty_ldisc_halt(struct tty_struct *tty)
-{
-       clear_bit(TTY_LDISC, &tty->flags);
-       return cancel_delayed_work_sync(&tty->buf.work);
-}
-
-/**
- *     tty_set_ldisc           -       set line discipline
- *     @tty: the terminal to set
- *     @ldisc: the line discipline
- *
- *     Set the discipline of a tty line. Must be called from a process
- *     context. The ldisc change logic has to protect itself against any
- *     overlapping ldisc change (including on the other end of pty pairs),
- *     the close of one side of a tty/pty pair, and eventually hangup.
- *
- *     Locking: takes tty_ldisc_lock, termios_mutex
- */
-
-int tty_set_ldisc(struct tty_struct *tty, int ldisc)
-{
-       int retval;
-       struct tty_ldisc *o_ldisc, *new_ldisc;
-       int work, o_work = 0;
-       struct tty_struct *o_tty;
-
-       new_ldisc = tty_ldisc_get(ldisc);
-       if (IS_ERR(new_ldisc))
-               return PTR_ERR(new_ldisc);
-
-       tty_lock();
-       /*
-        *      We need to look at the tty locking here for pty/tty pairs
-        *      when both sides try to change in parallel.
-        */
-
-       o_tty = tty->link;      /* o_tty is the pty side or NULL */
-
-
-       /*
-        *      Check the no-op case
-        */
-
-       if (tty->ldisc->ops->num == ldisc) {
-               tty_unlock();
-               tty_ldisc_put(new_ldisc);
-               return 0;
-       }
-
-       tty_unlock();
-       /*
-        *      Problem: What do we do if this blocks ?
-        *      We could deadlock here
-        */
-
-       tty_wait_until_sent(tty, 0);
-
-       tty_lock();
-       mutex_lock(&tty->ldisc_mutex);
-
-       /*
-        *      We could be midstream of another ldisc change which has
-        *      dropped the lock during processing. If so we need to wait.
-        */
-
-       while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
-               mutex_unlock(&tty->ldisc_mutex);
-               tty_unlock();
-               wait_event(tty_ldisc_wait,
-                       test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
-               tty_lock();
-               mutex_lock(&tty->ldisc_mutex);
-       }
-
-       set_bit(TTY_LDISC_CHANGING, &tty->flags);
-
-       /*
-        *      No more input please, we are switching. The new ldisc
-        *      will update this value in the ldisc open function
-        */
-
-       tty->receive_room = 0;
-
-       o_ldisc = tty->ldisc;
-
-       tty_unlock();
-       /*
-        *      Make sure we don't change while someone holds a
-        *      reference to the line discipline. The TTY_LDISC bit
-        *      prevents anyone taking a reference once it is clear.
-        *      We need the lock to avoid racing reference takers.
-        *
-        *      We must clear the TTY_LDISC bit here to avoid a livelock
-        *      with a userspace app continually trying to use the tty in
-        *      parallel to the change and re-referencing the tty.
-        */
-
-       work = tty_ldisc_halt(tty);
-       if (o_tty)
-               o_work = tty_ldisc_halt(o_tty);
-
-       /*
-        * Wait for ->hangup_work and ->buf.work handlers to terminate.
-        * We must drop the mutex here in case a hangup is also in process.
-        */
-
-       mutex_unlock(&tty->ldisc_mutex);
-
-       flush_scheduled_work();
-
-       tty_lock();
-       mutex_lock(&tty->ldisc_mutex);
-       if (test_bit(TTY_HUPPED, &tty->flags)) {
-               /* We were raced by the hangup method. It will have stomped
-                  the ldisc data and closed the ldisc down */
-               clear_bit(TTY_LDISC_CHANGING, &tty->flags);
-               mutex_unlock(&tty->ldisc_mutex);
-               tty_ldisc_put(new_ldisc);
-               tty_unlock();
-               return -EIO;
-       }
-
-       /* Shutdown the current discipline. */
-       tty_ldisc_close(tty, o_ldisc);
-
-       /* Now set up the new line discipline. */
-       tty_ldisc_assign(tty, new_ldisc);
-       tty_set_termios_ldisc(tty, ldisc);
-
-       retval = tty_ldisc_open(tty, new_ldisc);
-       if (retval < 0) {
-               /* Back to the old one or N_TTY if we can't */
-               tty_ldisc_put(new_ldisc);
-               tty_ldisc_restore(tty, o_ldisc);
-       }
-
-       /* At this point we hold a reference to the new ldisc and a
-          a reference to the old ldisc. If we ended up flipping back
-          to the existing ldisc we have two references to it */
-
-       if (tty->ldisc->ops->num != o_ldisc->ops->num && tty->ops->set_ldisc)
-               tty->ops->set_ldisc(tty);
-
-       tty_ldisc_put(o_ldisc);
-
-       /*
-        *      Allow ldisc referencing to occur again
-        */
-
-       tty_ldisc_enable(tty);
-       if (o_tty)
-               tty_ldisc_enable(o_tty);
-
-       /* Restart the work queue in case no characters kick it off. Safe if
-          already running */
-       if (work)
-               schedule_delayed_work(&tty->buf.work, 1);
-       if (o_work)
-               schedule_delayed_work(&o_tty->buf.work, 1);
-       mutex_unlock(&tty->ldisc_mutex);
-       tty_unlock();
-       return retval;
-}
-
-/**
- *     tty_reset_termios       -       reset terminal state
- *     @tty: tty to reset
- *
- *     Restore a terminal to the driver default state.
- */
-
-static void tty_reset_termios(struct tty_struct *tty)
-{
-       mutex_lock(&tty->termios_mutex);
-       *tty->termios = tty->driver->init_termios;
-       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
-       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
-       mutex_unlock(&tty->termios_mutex);
-}
-
-
-/**
- *     tty_ldisc_reinit        -       reinitialise the tty ldisc
- *     @tty: tty to reinit
- *     @ldisc: line discipline to reinitialize
- *
- *     Switch the tty to a line discipline and leave the ldisc
- *     state closed
- */
-
-static void tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
-{
-       struct tty_ldisc *ld;
-
-       tty_ldisc_close(tty, tty->ldisc);
-       tty_ldisc_put(tty->ldisc);
-       tty->ldisc = NULL;
-       /*
-        *      Switch the line discipline back
-        */
-       ld = tty_ldisc_get(ldisc);
-       BUG_ON(IS_ERR(ld));
-       tty_ldisc_assign(tty, ld);
-       tty_set_termios_ldisc(tty, ldisc);
-}
-
-/**
- *     tty_ldisc_hangup                -       hangup ldisc reset
- *     @tty: tty being hung up
- *
- *     Some tty devices reset their termios when they receive a hangup
- *     event. In that situation we must also switch back to N_TTY properly
- *     before we reset the termios data.
- *
- *     Locking: We can take the ldisc mutex as the rest of the code is
- *     careful to allow for this.
- *
- *     In the pty pair case this occurs in the close() path of the
- *     tty itself so we must be careful about locking rules.
- */
-
-void tty_ldisc_hangup(struct tty_struct *tty)
-{
-       struct tty_ldisc *ld;
-       int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;
-       int err = 0;
-
-       /*
-        * FIXME! What are the locking issues here? This may me overdoing
-        * things... This question is especially important now that we've
-        * removed the irqlock.
-        */
-       ld = tty_ldisc_ref(tty);
-       if (ld != NULL) {
-               /* We may have no line discipline at this point */
-               if (ld->ops->flush_buffer)
-                       ld->ops->flush_buffer(tty);
-               tty_driver_flush_buffer(tty);
-               if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
-                   ld->ops->write_wakeup)
-                       ld->ops->write_wakeup(tty);
-               if (ld->ops->hangup)
-                       ld->ops->hangup(tty);
-               tty_ldisc_deref(ld);
-       }
-       /*
-        * FIXME: Once we trust the LDISC code better we can wait here for
-        * ldisc completion and fix the driver call race
-        */
-       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
-       wake_up_interruptible_poll(&tty->read_wait, POLLIN);
-       /*
-        * Shutdown the current line discipline, and reset it to
-        * N_TTY if need be.
-        *
-        * Avoid racing set_ldisc or tty_ldisc_release
-        */
-       mutex_lock(&tty->ldisc_mutex);
-
-       /*
-        * this is like tty_ldisc_halt, but we need to give up
-        * the BTM before calling cancel_delayed_work_sync,
-        * which may need to wait for another function taking the BTM
-        */
-       clear_bit(TTY_LDISC, &tty->flags);
-       tty_unlock();
-       cancel_delayed_work_sync(&tty->buf.work);
-       mutex_unlock(&tty->ldisc_mutex);
-
-       tty_lock();
-       mutex_lock(&tty->ldisc_mutex);
-
-       /* At this point we have a closed ldisc and we want to
-          reopen it. We could defer this to the next open but
-          it means auditing a lot of other paths so this is
-          a FIXME */
-       if (tty->ldisc) {       /* Not yet closed */
-               if (reset == 0) {
-                       tty_ldisc_reinit(tty, tty->termios->c_line);
-                       err = tty_ldisc_open(tty, tty->ldisc);
-               }
-               /* If the re-open fails or we reset then go to N_TTY. The
-                  N_TTY open cannot fail */
-               if (reset || err) {
-                       tty_ldisc_reinit(tty, N_TTY);
-                       WARN_ON(tty_ldisc_open(tty, tty->ldisc));
-               }
-               tty_ldisc_enable(tty);
-       }
-       mutex_unlock(&tty->ldisc_mutex);
-       if (reset)
-               tty_reset_termios(tty);
-}
-
-/**
- *     tty_ldisc_setup                 -       open line discipline
- *     @tty: tty being shut down
- *     @o_tty: pair tty for pty/tty pairs
- *
- *     Called during the initial open of a tty/pty pair in order to set up the
- *     line disciplines and bind them to the tty. This has no locking issues
- *     as the device isn't yet active.
- */
-
-int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
-{
-       struct tty_ldisc *ld = tty->ldisc;
-       int retval;
-
-       retval = tty_ldisc_open(tty, ld);
-       if (retval)
-               return retval;
-
-       if (o_tty) {
-               retval = tty_ldisc_open(o_tty, o_tty->ldisc);
-               if (retval) {
-                       tty_ldisc_close(tty, ld);
-                       return retval;
-               }
-               tty_ldisc_enable(o_tty);
-       }
-       tty_ldisc_enable(tty);
-       return 0;
-}
-/**
- *     tty_ldisc_release               -       release line discipline
- *     @tty: tty being shut down
- *     @o_tty: pair tty for pty/tty pairs
- *
- *     Called during the final close of a tty/pty pair in order to shut down
- *     the line discpline layer. On exit the ldisc assigned is N_TTY and the
- *     ldisc has not been opened.
- */
-
-void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
-{
-       /*
-        * Prevent flush_to_ldisc() from rescheduling the work for later.  Then
-        * kill any delayed work. As this is the final close it does not
-        * race with the set_ldisc code path.
-        */
-
-       tty_unlock();
-       tty_ldisc_halt(tty);
-       flush_scheduled_work();
-       tty_lock();
-
-       mutex_lock(&tty->ldisc_mutex);
-       /*
-        * Now kill off the ldisc
-        */
-       tty_ldisc_close(tty, tty->ldisc);
-       tty_ldisc_put(tty->ldisc);
-       /* Force an oops if we mess this up */
-       tty->ldisc = NULL;
-
-       /* Ensure the next open requests the N_TTY ldisc */
-       tty_set_termios_ldisc(tty, N_TTY);
-       mutex_unlock(&tty->ldisc_mutex);
-
-       /* This will need doing differently if we need to lock */
-       if (o_tty)
-               tty_ldisc_release(o_tty, NULL);
-
-       /* And the memory resources remaining (buffers, termios) will be
-          disposed of when the kref hits zero */
-}
-
-/**
- *     tty_ldisc_init          -       ldisc setup for new tty
- *     @tty: tty being allocated
- *
- *     Set up the line discipline objects for a newly allocated tty. Note that
- *     the tty structure is not completely set up when this call is made.
- */
-
-void tty_ldisc_init(struct tty_struct *tty)
-{
-       struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
-       if (IS_ERR(ld))
-               panic("n_tty: init_tty");
-       tty_ldisc_assign(tty, ld);
-}
-
-void tty_ldisc_begin(void)
-{
-       /* Setup the default TTY line discipline. */
-       (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
-}
diff --git a/drivers/char/tty_mutex.c b/drivers/char/tty_mutex.c
deleted file mode 100644 (file)
index 1336975..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * drivers/char/tty_lock.c
- */
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/kallsyms.h>
-#include <linux/semaphore.h>
-#include <linux/sched.h>
-
-/*
- * The 'big tty mutex'
- *
- * This mutex is taken and released by tty_lock() and tty_unlock(),
- * replacing the older big kernel lock.
- * It can no longer be taken recursively, and does not get
- * released implicitly while sleeping.
- *
- * Don't use in new code.
- */
-static DEFINE_MUTEX(big_tty_mutex);
-struct task_struct *__big_tty_mutex_owner;
-EXPORT_SYMBOL_GPL(__big_tty_mutex_owner);
-
-/*
- * Getting the big tty mutex.
- */
-void __lockfunc tty_lock(void)
-{
-       struct task_struct *task = current;
-
-       WARN_ON(__big_tty_mutex_owner == task);
-
-       mutex_lock(&big_tty_mutex);
-       __big_tty_mutex_owner = task;
-}
-EXPORT_SYMBOL(tty_lock);
-
-void __lockfunc tty_unlock(void)
-{
-       struct task_struct *task = current;
-
-       WARN_ON(__big_tty_mutex_owner != task);
-       __big_tty_mutex_owner = NULL;
-
-       mutex_unlock(&big_tty_mutex);
-}
-EXPORT_SYMBOL(tty_unlock);
diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
deleted file mode 100644 (file)
index 33d37d2..0000000
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Tty port functions
- */
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-
-void tty_port_init(struct tty_port *port)
-{
-       memset(port, 0, sizeof(*port));
-       init_waitqueue_head(&port->open_wait);
-       init_waitqueue_head(&port->close_wait);
-       init_waitqueue_head(&port->delta_msr_wait);
-       mutex_init(&port->mutex);
-       mutex_init(&port->buf_mutex);
-       spin_lock_init(&port->lock);
-       port->close_delay = (50 * HZ) / 100;
-       port->closing_wait = (3000 * HZ) / 100;
-       kref_init(&port->kref);
-}
-EXPORT_SYMBOL(tty_port_init);
-
-int tty_port_alloc_xmit_buf(struct tty_port *port)
-{
-       /* We may sleep in get_zeroed_page() */
-       mutex_lock(&port->buf_mutex);
-       if (port->xmit_buf == NULL)
-               port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
-       mutex_unlock(&port->buf_mutex);
-       if (port->xmit_buf == NULL)
-               return -ENOMEM;
-       return 0;
-}
-EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
-
-void tty_port_free_xmit_buf(struct tty_port *port)
-{
-       mutex_lock(&port->buf_mutex);
-       if (port->xmit_buf != NULL) {
-               free_page((unsigned long)port->xmit_buf);
-               port->xmit_buf = NULL;
-       }
-       mutex_unlock(&port->buf_mutex);
-}
-EXPORT_SYMBOL(tty_port_free_xmit_buf);
-
-static void tty_port_destructor(struct kref *kref)
-{
-       struct tty_port *port = container_of(kref, struct tty_port, kref);
-       if (port->xmit_buf)
-               free_page((unsigned long)port->xmit_buf);
-       if (port->ops->destruct)
-               port->ops->destruct(port);
-       else
-               kfree(port);
-}
-
-void tty_port_put(struct tty_port *port)
-{
-       if (port)
-               kref_put(&port->kref, tty_port_destructor);
-}
-EXPORT_SYMBOL(tty_port_put);
-
-/**
- *     tty_port_tty_get        -       get a tty reference
- *     @port: tty port
- *
- *     Return a refcount protected tty instance or NULL if the port is not
- *     associated with a tty (eg due to close or hangup)
- */
-
-struct tty_struct *tty_port_tty_get(struct tty_port *port)
-{
-       unsigned long flags;
-       struct tty_struct *tty;
-
-       spin_lock_irqsave(&port->lock, flags);
-       tty = tty_kref_get(port->tty);
-       spin_unlock_irqrestore(&port->lock, flags);
-       return tty;
-}
-EXPORT_SYMBOL(tty_port_tty_get);
-
-/**
- *     tty_port_tty_set        -       set the tty of a port
- *     @port: tty port
- *     @tty: the tty
- *
- *     Associate the port and tty pair. Manages any internal refcounts.
- *     Pass NULL to deassociate a port
- */
-
-void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       if (port->tty)
-               tty_kref_put(port->tty);
-       port->tty = tty_kref_get(tty);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-EXPORT_SYMBOL(tty_port_tty_set);
-
-static void tty_port_shutdown(struct tty_port *port)
-{
-       mutex_lock(&port->mutex);
-       if (port->ops->shutdown && !port->console &&
-               test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
-                       port->ops->shutdown(port);
-       mutex_unlock(&port->mutex);
-}
-
-/**
- *     tty_port_hangup         -       hangup helper
- *     @port: tty port
- *
- *     Perform port level tty hangup flag and count changes. Drop the tty
- *     reference.
- */
-
-void tty_port_hangup(struct tty_port *port)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       port->count = 0;
-       port->flags &= ~ASYNC_NORMAL_ACTIVE;
-       if (port->tty) {
-               set_bit(TTY_IO_ERROR, &port->tty->flags);
-               tty_kref_put(port->tty);
-       }
-       port->tty = NULL;
-       spin_unlock_irqrestore(&port->lock, flags);
-       wake_up_interruptible(&port->open_wait);
-       wake_up_interruptible(&port->delta_msr_wait);
-       tty_port_shutdown(port);
-}
-EXPORT_SYMBOL(tty_port_hangup);
-
-/**
- *     tty_port_carrier_raised -       carrier raised check
- *     @port: tty port
- *
- *     Wrapper for the carrier detect logic. For the moment this is used
- *     to hide some internal details. This will eventually become entirely
- *     internal to the tty port.
- */
-
-int tty_port_carrier_raised(struct tty_port *port)
-{
-       if (port->ops->carrier_raised == NULL)
-               return 1;
-       return port->ops->carrier_raised(port);
-}
-EXPORT_SYMBOL(tty_port_carrier_raised);
-
-/**
- *     tty_port_raise_dtr_rts  -       Raise DTR/RTS
- *     @port: tty port
- *
- *     Wrapper for the DTR/RTS raise logic. For the moment this is used
- *     to hide some internal details. This will eventually become entirely
- *     internal to the tty port.
- */
-
-void tty_port_raise_dtr_rts(struct tty_port *port)
-{
-       if (port->ops->dtr_rts)
-               port->ops->dtr_rts(port, 1);
-}
-EXPORT_SYMBOL(tty_port_raise_dtr_rts);
-
-/**
- *     tty_port_lower_dtr_rts  -       Lower DTR/RTS
- *     @port: tty port
- *
- *     Wrapper for the DTR/RTS raise logic. For the moment this is used
- *     to hide some internal details. This will eventually become entirely
- *     internal to the tty port.
- */
-
-void tty_port_lower_dtr_rts(struct tty_port *port)
-{
-       if (port->ops->dtr_rts)
-               port->ops->dtr_rts(port, 0);
-}
-EXPORT_SYMBOL(tty_port_lower_dtr_rts);
-
-/**
- *     tty_port_block_til_ready        -       Waiting logic for tty open
- *     @port: the tty port being opened
- *     @tty: the tty device being bound
- *     @filp: the file pointer of the opener
- *
- *     Implement the core POSIX/SuS tty behaviour when opening a tty device.
- *     Handles:
- *             - hangup (both before and during)
- *             - non blocking open
- *             - rts/dtr/dcd
- *             - signals
- *             - port flags and counts
- *
- *     The passed tty_port must implement the carrier_raised method if it can
- *     do carrier detect and the dtr_rts method if it supports software
- *     management of these lines. Note that the dtr/rts raise is done each
- *     iteration as a hangup may have previously dropped them while we wait.
- */
-
-int tty_port_block_til_ready(struct tty_port *port,
-                               struct tty_struct *tty, struct file *filp)
-{
-       int do_clocal = 0, retval;
-       unsigned long flags;
-       DEFINE_WAIT(wait);
-       int cd;
-
-       /* block if port is in the process of being closed */
-       if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
-               wait_event_interruptible_tty(port->close_wait,
-                               !(port->flags & ASYNC_CLOSING));
-               if (port->flags & ASYNC_HUP_NOTIFY)
-                       return -EAGAIN;
-               else
-                       return -ERESTARTSYS;
-       }
-
-       /* if non-blocking mode is set we can pass directly to open unless
-          the port has just hung up or is in another error state */
-       if (tty->flags & (1 << TTY_IO_ERROR)) {
-               port->flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-       if (filp->f_flags & O_NONBLOCK) {
-               /* Indicate we are open */
-               if (tty->termios->c_cflag & CBAUD)
-                       tty_port_raise_dtr_rts(port);
-               port->flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
-
-       if (C_CLOCAL(tty))
-               do_clocal = 1;
-
-       /* Block waiting until we can proceed. We may need to wait for the
-          carrier, but we must also wait for any close that is in progress
-          before the next open may complete */
-
-       retval = 0;
-
-       /* The port lock protects the port counts */
-       spin_lock_irqsave(&port->lock, flags);
-       if (!tty_hung_up_p(filp))
-               port->count--;
-       port->blocked_open++;
-       spin_unlock_irqrestore(&port->lock, flags);
-
-       while (1) {
-               /* Indicate we are open */
-               if (tty->termios->c_cflag & CBAUD)
-                       tty_port_raise_dtr_rts(port);
-
-               prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
-               /* Check for a hangup or uninitialised port.
-                                                       Return accordingly */
-               if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
-                       if (port->flags & ASYNC_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;
-                       break;
-               }
-               /* Probe the carrier. For devices with no carrier detect this
-                  will always return true */
-               cd = tty_port_carrier_raised(port);
-               if (!(port->flags & ASYNC_CLOSING) &&
-                               (do_clocal || cd))
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               tty_unlock();
-               schedule();
-               tty_lock();
-       }
-       finish_wait(&port->open_wait, &wait);
-
-       /* Update counts. A parallel hangup will have set count to zero and
-          we must not mess that up further */
-       spin_lock_irqsave(&port->lock, flags);
-       if (!tty_hung_up_p(filp))
-               port->count++;
-       port->blocked_open--;
-       if (retval == 0)
-               port->flags |= ASYNC_NORMAL_ACTIVE;
-       spin_unlock_irqrestore(&port->lock, flags);
-       return retval;
-}
-EXPORT_SYMBOL(tty_port_block_til_ready);
-
-int tty_port_close_start(struct tty_port *port,
-                               struct tty_struct *tty, struct file *filp)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       if (tty_hung_up_p(filp)) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               return 0;
-       }
-
-       if (tty->count == 1 && port->count != 1) {
-               printk(KERN_WARNING
-                   "tty_port_close_start: tty->count = 1 port count = %d.\n",
-                                                               port->count);
-               port->count = 1;
-       }
-       if (--port->count < 0) {
-               printk(KERN_WARNING "tty_port_close_start: count = %d\n",
-                                                               port->count);
-               port->count = 0;
-       }
-
-       if (port->count) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               if (port->ops->drop)
-                       port->ops->drop(port);
-               return 0;
-       }
-       set_bit(ASYNCB_CLOSING, &port->flags);
-       tty->closing = 1;
-       spin_unlock_irqrestore(&port->lock, flags);
-       /* Don't block on a stalled port, just pull the chain */
-       if (tty->flow_stopped)
-               tty_driver_flush_buffer(tty);
-       if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
-                       port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, port->closing_wait);
-       if (port->drain_delay) {
-               unsigned int bps = tty_get_baud_rate(tty);
-               long timeout;
-
-               if (bps > 1200)
-                       timeout = max_t(long,
-                               (HZ * 10 * port->drain_delay) / bps, HZ / 10);
-               else
-                       timeout = 2 * HZ;
-               schedule_timeout_interruptible(timeout);
-       }
-       /* Flush the ldisc buffering */
-       tty_ldisc_flush(tty);
-
-       /* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
-          hang up the line */
-       if (tty->termios->c_cflag & HUPCL)
-               tty_port_lower_dtr_rts(port);
-
-       /* Don't call port->drop for the last reference. Callers will want
-          to drop the last active reference in ->shutdown() or the tty
-          shutdown path */
-       return 1;
-}
-EXPORT_SYMBOL(tty_port_close_start);
-
-void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&port->lock, flags);
-       tty->closing = 0;
-
-       if (port->blocked_open) {
-               spin_unlock_irqrestore(&port->lock, flags);
-               if (port->close_delay) {
-                       msleep_interruptible(
-                               jiffies_to_msecs(port->close_delay));
-               }
-               spin_lock_irqsave(&port->lock, flags);
-               wake_up_interruptible(&port->open_wait);
-       }
-       port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
-       wake_up_interruptible(&port->close_wait);
-       spin_unlock_irqrestore(&port->lock, flags);
-}
-EXPORT_SYMBOL(tty_port_close_end);
-
-void tty_port_close(struct tty_port *port, struct tty_struct *tty,
-                                                       struct file *filp)
-{
-       if (tty_port_close_start(port, tty, filp) == 0)
-               return;
-       tty_port_shutdown(port);
-       set_bit(TTY_IO_ERROR, &tty->flags);
-       tty_port_close_end(port, tty);
-       tty_port_tty_set(port, NULL);
-}
-EXPORT_SYMBOL(tty_port_close);
-
-int tty_port_open(struct tty_port *port, struct tty_struct *tty,
-                                                       struct file *filp)
-{
-       spin_lock_irq(&port->lock);
-       if (!tty_hung_up_p(filp))
-               ++port->count;
-       spin_unlock_irq(&port->lock);
-       tty_port_tty_set(port, tty);
-
-       /*
-        * Do the device-specific open only if the hardware isn't
-        * already initialized. Serialize open and shutdown using the
-        * port mutex.
-        */
-
-       mutex_lock(&port->mutex);
-
-       if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
-               clear_bit(TTY_IO_ERROR, &tty->flags);
-               if (port->ops->activate) {
-                       int retval = port->ops->activate(port, tty);
-                       if (retval) {
-                               mutex_unlock(&port->mutex);
-                               return retval;
-                       }
-               }
-               set_bit(ASYNCB_INITIALIZED, &port->flags);
-       }
-       mutex_unlock(&port->mutex);
-       return tty_port_block_til_ready(port, tty, filp);
-}
-
-EXPORT_SYMBOL(tty_port_open);
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
deleted file mode 100644 (file)
index 273ab44..0000000
+++ /dev/null
@@ -1,644 +0,0 @@
-/*
- * linux/drivers/char/vc_screen.c
- *
- * Provide access to virtual console memory.
- * /dev/vcs0: the screen as it is being viewed right now (possibly scrolled)
- * /dev/vcsN: the screen of /dev/ttyN (1 <= N <= 63)
- *            [minor: N]
- *
- * /dev/vcsaN: idem, but including attributes, and prefixed with
- *     the 4 bytes lines,columns,x,y (as screendump used to give).
- *     Attribute/character pair is in native endianity.
- *            [minor: N+128]
- *
- * This replaces screendump and part of selection, so that the system
- * administrator can control access using file system permissions.
- *
- * aeb@cwi.nl - efter Friedas begravelse - 950211
- *
- * machek@k332.feld.cvut.cz - modified not to send characters to wrong console
- *      - fixed some fatal off-by-one bugs (0-- no longer == -1 -> looping and looping and looping...)
- *      - making it shorter - scr_readw are macros which expand in PRETTY long code
- */
-
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/errno.h>
-#include <linux/tty.h>
-#include <linux/interrupt.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/mutex.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-#include <linux/kbd_kern.h>
-#include <linux/console.h>
-#include <linux/device.h>
-#include <linux/smp_lock.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/signal.h>
-#include <linux/slab.h>
-#include <linux/notifier.h>
-
-#include <asm/uaccess.h>
-#include <asm/byteorder.h>
-#include <asm/unaligned.h>
-
-#undef attr
-#undef org
-#undef addr
-#define HEADER_SIZE    4
-
-struct vcs_poll_data {
-       struct notifier_block notifier;
-       unsigned int cons_num;
-       bool seen_last_update;
-       wait_queue_head_t waitq;
-       struct fasync_struct *fasync;
-};
-
-static int
-vcs_notifier(struct notifier_block *nb, unsigned long code, void *_param)
-{
-       struct vt_notifier_param *param = _param;
-       struct vc_data *vc = param->vc;
-       struct vcs_poll_data *poll =
-               container_of(nb, struct vcs_poll_data, notifier);
-       int currcons = poll->cons_num;
-
-       if (code != VT_UPDATE)
-               return NOTIFY_DONE;
-
-       if (currcons == 0)
-               currcons = fg_console;
-       else
-               currcons--;
-       if (currcons != vc->vc_num)
-               return NOTIFY_DONE;
-
-       poll->seen_last_update = false;
-       wake_up_interruptible(&poll->waitq);
-       kill_fasync(&poll->fasync, SIGIO, POLL_IN);
-       return NOTIFY_OK;
-}
-
-static void
-vcs_poll_data_free(struct vcs_poll_data *poll)
-{
-       unregister_vt_notifier(&poll->notifier);
-       kfree(poll);
-}
-
-static struct vcs_poll_data *
-vcs_poll_data_get(struct file *file)
-{
-       struct vcs_poll_data *poll = file->private_data;
-
-       if (poll)
-               return poll;
-
-       poll = kzalloc(sizeof(*poll), GFP_KERNEL);
-       if (!poll)
-               return NULL;
-       poll->cons_num = iminor(file->f_path.dentry->d_inode) & 127;
-       init_waitqueue_head(&poll->waitq);
-       poll->notifier.notifier_call = vcs_notifier;
-       if (register_vt_notifier(&poll->notifier) != 0) {
-               kfree(poll);
-               return NULL;
-       }
-
-       /*
-        * This code may be called either through ->poll() or ->fasync().
-        * If we have two threads using the same file descriptor, they could
-        * both enter this function, both notice that the structure hasn't
-        * been allocated yet and go ahead allocating it in parallel, but
-        * only one of them must survive and be shared otherwise we'd leak
-        * memory with a dangling notifier callback.
-        */
-       spin_lock(&file->f_lock);
-       if (!file->private_data) {
-               file->private_data = poll;
-       } else {
-               /* someone else raced ahead of us */
-               vcs_poll_data_free(poll);
-               poll = file->private_data;
-       }
-       spin_unlock(&file->f_lock);
-
-       return poll;
-}
-
-static int
-vcs_size(struct inode *inode)
-{
-       int size;
-       int minor = iminor(inode);
-       int currcons = minor & 127;
-       struct vc_data *vc;
-
-       if (currcons == 0)
-               currcons = fg_console;
-       else
-               currcons--;
-       if (!vc_cons_allocated(currcons))
-               return -ENXIO;
-       vc = vc_cons[currcons].d;
-
-       size = vc->vc_rows * vc->vc_cols;
-
-       if (minor & 128)
-               size = 2*size + HEADER_SIZE;
-       return size;
-}
-
-static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
-{
-       int size;
-
-       mutex_lock(&con_buf_mtx);
-       size = vcs_size(file->f_path.dentry->d_inode);
-       switch (orig) {
-               default:
-                       mutex_unlock(&con_buf_mtx);
-                       return -EINVAL;
-               case 2:
-                       offset += size;
-                       break;
-               case 1:
-                       offset += file->f_pos;
-               case 0:
-                       break;
-       }
-       if (offset < 0 || offset > size) {
-               mutex_unlock(&con_buf_mtx);
-               return -EINVAL;
-       }
-       file->f_pos = offset;
-       mutex_unlock(&con_buf_mtx);
-       return file->f_pos;
-}
-
-
-static ssize_t
-vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
-{
-       struct inode *inode = file->f_path.dentry->d_inode;
-       unsigned int currcons = iminor(inode);
-       struct vc_data *vc;
-       struct vcs_poll_data *poll;
-       long pos;
-       long viewed, attr, read;
-       int col, maxcol;
-       unsigned short *org = NULL;
-       ssize_t ret;
-
-       mutex_lock(&con_buf_mtx);
-
-       pos = *ppos;
-
-       /* Select the proper current console and verify
-        * sanity of the situation under the console lock.
-        */
-       acquire_console_sem();
-
-       attr = (currcons & 128);
-       currcons = (currcons & 127);
-       if (currcons == 0) {
-               currcons = fg_console;
-               viewed = 1;
-       } else {
-               currcons--;
-               viewed = 0;
-       }
-       ret = -ENXIO;
-       if (!vc_cons_allocated(currcons))
-               goto unlock_out;
-       vc = vc_cons[currcons].d;
-
-       ret = -EINVAL;
-       if (pos < 0)
-               goto unlock_out;
-       poll = file->private_data;
-       if (count && poll)
-               poll->seen_last_update = true;
-       read = 0;
-       ret = 0;
-       while (count) {
-               char *con_buf0, *con_buf_start;
-               long this_round, size;
-               ssize_t orig_count;
-               long p = pos;
-
-               /* Check whether we are above size each round,
-                * as copy_to_user at the end of this loop
-                * could sleep.
-                */
-               size = vcs_size(inode);
-               if (pos >= size)
-                       break;
-               if (count > size - pos)
-                       count = size - pos;
-
-               this_round = count;
-               if (this_round > CON_BUF_SIZE)
-                       this_round = CON_BUF_SIZE;
-
-               /* Perform the whole read into the local con_buf.
-                * Then we can drop the console spinlock and safely
-                * attempt to move it to userspace.
-                */
-
-               con_buf_start = con_buf0 = con_buf;
-               orig_count = this_round;
-               maxcol = vc->vc_cols;
-               if (!attr) {
-                       org = screen_pos(vc, p, viewed);
-                       col = p % maxcol;
-                       p += maxcol - col;
-                       while (this_round-- > 0) {
-                               *con_buf0++ = (vcs_scr_readw(vc, org++) & 0xff);
-                               if (++col == maxcol) {
-                                       org = screen_pos(vc, p, viewed);
-                                       col = 0;
-                                       p += maxcol;
-                               }
-                       }
-               } else {
-                       if (p < HEADER_SIZE) {
-                               size_t tmp_count;
-
-                               con_buf0[0] = (char)vc->vc_rows;
-                               con_buf0[1] = (char)vc->vc_cols;
-                               getconsxy(vc, con_buf0 + 2);
-
-                               con_buf_start += p;
-                               this_round += p;
-                               if (this_round > CON_BUF_SIZE) {
-                                       this_round = CON_BUF_SIZE;
-                                       orig_count = this_round - p;
-                               }
-
-                               tmp_count = HEADER_SIZE;
-                               if (tmp_count > this_round)
-                                       tmp_count = this_round;
-
-                               /* Advance state pointers and move on. */
-                               this_round -= tmp_count;
-                               p = HEADER_SIZE;
-                               con_buf0 = con_buf + HEADER_SIZE;
-                               /* If this_round >= 0, then p is even... */
-                       } else if (p & 1) {
-                               /* Skip first byte for output if start address is odd
-                                * Update region sizes up/down depending on free
-                                * space in buffer.
-                                */
-                               con_buf_start++;
-                               if (this_round < CON_BUF_SIZE)
-                                       this_round++;
-                               else
-                                       orig_count--;
-                       }
-                       if (this_round > 0) {
-                               unsigned short *tmp_buf = (unsigned short *)con_buf0;
-
-                               p -= HEADER_SIZE;
-                               p /= 2;
-                               col = p % maxcol;
-
-                               org = screen_pos(vc, p, viewed);
-                               p += maxcol - col;
-
-                               /* Buffer has even length, so we can always copy
-                                * character + attribute. We do not copy last byte
-                                * to userspace if this_round is odd.
-                                */
-                               this_round = (this_round + 1) >> 1;
-
-                               while (this_round) {
-                                       *tmp_buf++ = vcs_scr_readw(vc, org++);
-                                       this_round --;
-                                       if (++col == maxcol) {
-                                               org = screen_pos(vc, p, viewed);
-                                               col = 0;
-                                               p += maxcol;
-                                       }
-                               }
-                       }
-               }
-
-               /* Finally, release the console semaphore while we push
-                * all the data to userspace from our temporary buffer.
-                *
-                * AKPM: Even though it's a semaphore, we should drop it because
-                * the pagefault handling code may want to call printk().
-                */
-
-               release_console_sem();
-               ret = copy_to_user(buf, con_buf_start, orig_count);
-               acquire_console_sem();
-
-               if (ret) {
-                       read += (orig_count - ret);
-                       ret = -EFAULT;
-                       break;
-               }
-               buf += orig_count;
-               pos += orig_count;
-               read += orig_count;
-               count -= orig_count;
-       }
-       *ppos += read;
-       if (read)
-               ret = read;
-unlock_out:
-       release_console_sem();
-       mutex_unlock(&con_buf_mtx);
-       return ret;
-}
-
-static ssize_t
-vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
-{
-       struct inode *inode = file->f_path.dentry->d_inode;
-       unsigned int currcons = iminor(inode);
-       struct vc_data *vc;
-       long pos;
-       long viewed, attr, size, written;
-       char *con_buf0;
-       int col, maxcol;
-       u16 *org0 = NULL, *org = NULL;
-       size_t ret;
-
-       mutex_lock(&con_buf_mtx);
-
-       pos = *ppos;
-
-       /* Select the proper current console and verify
-        * sanity of the situation under the console lock.
-        */
-       acquire_console_sem();
-
-       attr = (currcons & 128);
-       currcons = (currcons & 127);
-
-       if (currcons == 0) {
-               currcons = fg_console;
-               viewed = 1;
-       } else {
-               currcons--;
-               viewed = 0;
-       }
-       ret = -ENXIO;
-       if (!vc_cons_allocated(currcons))
-               goto unlock_out;
-       vc = vc_cons[currcons].d;
-
-       size = vcs_size(inode);
-       ret = -EINVAL;
-       if (pos < 0 || pos > size)
-               goto unlock_out;
-       if (count > size - pos)
-               count = size - pos;
-       written = 0;
-       while (count) {
-               long this_round = count;
-               size_t orig_count;
-               long p;
-
-               if (this_round > CON_BUF_SIZE)
-                       this_round = CON_BUF_SIZE;
-
-               /* Temporarily drop the console lock so that we can read
-                * in the write data from userspace safely.
-                */
-               release_console_sem();
-               ret = copy_from_user(con_buf, buf, this_round);
-               acquire_console_sem();
-
-               if (ret) {
-                       this_round -= ret;
-                       if (!this_round) {
-                               /* Abort loop if no data were copied. Otherwise
-                                * fail with -EFAULT.
-                                */
-                               if (written)
-                                       break;
-                               ret = -EFAULT;
-                               goto unlock_out;
-                       }
-               }
-
-               /* The vcs_size might have changed while we slept to grab
-                * the user buffer, so recheck.
-                * Return data written up to now on failure.
-                */
-               size = vcs_size(inode);
-               if (pos >= size)
-                       break;
-               if (this_round > size - pos)
-                       this_round = size - pos;
-
-               /* OK, now actually push the write to the console
-                * under the lock using the local kernel buffer.
-                */
-
-               con_buf0 = con_buf;
-               orig_count = this_round;
-               maxcol = vc->vc_cols;
-               p = pos;
-               if (!attr) {
-                       org0 = org = screen_pos(vc, p, viewed);
-                       col = p % maxcol;
-                       p += maxcol - col;
-
-                       while (this_round > 0) {
-                               unsigned char c = *con_buf0++;
-
-                               this_round--;
-                               vcs_scr_writew(vc,
-                                              (vcs_scr_readw(vc, org) & 0xff00) | c, org);
-                               org++;
-                               if (++col == maxcol) {
-                                       org = screen_pos(vc, p, viewed);
-                                       col = 0;
-                                       p += maxcol;
-                               }
-                       }
-               } else {
-                       if (p < HEADER_SIZE) {
-                               char header[HEADER_SIZE];
-
-                               getconsxy(vc, header + 2);
-                               while (p < HEADER_SIZE && this_round > 0) {
-                                       this_round--;
-                                       header[p++] = *con_buf0++;
-                               }
-                               if (!viewed)
-                                       putconsxy(vc, header + 2);
-                       }
-                       p -= HEADER_SIZE;
-                       col = (p/2) % maxcol;
-                       if (this_round > 0) {
-                               org0 = org = screen_pos(vc, p/2, viewed);
-                               if ((p & 1) && this_round > 0) {
-                                       char c;
-
-                                       this_round--;
-                                       c = *con_buf0++;
-#ifdef __BIG_ENDIAN
-                                       vcs_scr_writew(vc, c |
-                                            (vcs_scr_readw(vc, org) & 0xff00), org);
-#else
-                                       vcs_scr_writew(vc, (c << 8) |
-                                            (vcs_scr_readw(vc, org) & 0xff), org);
-#endif
-                                       org++;
-                                       p++;
-                                       if (++col == maxcol) {
-                                               org = screen_pos(vc, p/2, viewed);
-                                               col = 0;
-                                       }
-                               }
-                               p /= 2;
-                               p += maxcol - col;
-                       }
-                       while (this_round > 1) {
-                               unsigned short w;
-
-                               w = get_unaligned(((unsigned short *)con_buf0));
-                               vcs_scr_writew(vc, w, org++);
-                               con_buf0 += 2;
-                               this_round -= 2;
-                               if (++col == maxcol) {
-                                       org = screen_pos(vc, p, viewed);
-                                       col = 0;
-                                       p += maxcol;
-                               }
-                       }
-                       if (this_round > 0) {
-                               unsigned char c;
-
-                               c = *con_buf0++;
-#ifdef __BIG_ENDIAN
-                               vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff) | (c << 8), org);
-#else
-                               vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff00) | c, org);
-#endif
-                       }
-               }
-               count -= orig_count;
-               written += orig_count;
-               buf += orig_count;
-               pos += orig_count;
-               if (org0)
-                       update_region(vc, (unsigned long)(org0), org - org0);
-       }
-       *ppos += written;
-       ret = written;
-       if (written)
-               vcs_scr_updated(vc);
-
-unlock_out:
-       release_console_sem();
-
-       mutex_unlock(&con_buf_mtx);
-
-       return ret;
-}
-
-static unsigned int
-vcs_poll(struct file *file, poll_table *wait)
-{
-       struct vcs_poll_data *poll = vcs_poll_data_get(file);
-       int ret = 0;
-
-       if (poll) {
-               poll_wait(file, &poll->waitq, wait);
-               if (!poll->seen_last_update)
-                       ret = POLLIN | POLLRDNORM;
-       }
-       return ret;
-}
-
-static int
-vcs_fasync(int fd, struct file *file, int on)
-{
-       struct vcs_poll_data *poll = file->private_data;
-
-       if (!poll) {
-               /* don't allocate anything if all we want is disable fasync */
-               if (!on)
-                       return 0;
-               poll = vcs_poll_data_get(file);
-               if (!poll)
-                       return -ENOMEM;
-       }
-
-       return fasync_helper(fd, file, on, &poll->fasync);
-}
-
-static int
-vcs_open(struct inode *inode, struct file *filp)
-{
-       unsigned int currcons = iminor(inode) & 127;
-       int ret = 0;
-       
-       tty_lock();
-       if(currcons && !vc_cons_allocated(currcons-1))
-               ret = -ENXIO;
-       tty_unlock();
-       return ret;
-}
-
-static int vcs_release(struct inode *inode, struct file *file)
-{
-       struct vcs_poll_data *poll = file->private_data;
-
-       if (poll)
-               vcs_poll_data_free(poll);
-       return 0;
-}
-
-static const struct file_operations vcs_fops = {
-       .llseek         = vcs_lseek,
-       .read           = vcs_read,
-       .write          = vcs_write,
-       .poll           = vcs_poll,
-       .fasync         = vcs_fasync,
-       .open           = vcs_open,
-       .release        = vcs_release,
-};
-
-static struct class *vc_class;
-
-void vcs_make_sysfs(int index)
-{
-       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 1), NULL,
-                     "vcs%u", index + 1);
-       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 129), NULL,
-                     "vcsa%u", index + 1);
-}
-
-void vcs_remove_sysfs(int index)
-{
-       device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 1));
-       device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 129));
-}
-
-int __init vcs_init(void)
-{
-       unsigned int i;
-
-       if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops))
-               panic("unable to get major %d for vcs device", VCS_MAJOR);
-       vc_class = class_create(THIS_MODULE, "vc");
-
-       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs");
-       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa");
-       for (i = 0; i < MIN_NR_CONSOLES; i++)
-               vcs_make_sysfs(i);
-       return 0;
-}
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
deleted file mode 100644 (file)
index a8ec48e..0000000
+++ /dev/null
@@ -1,4209 +0,0 @@
-/*
- *  linux/drivers/char/vt.c
- *
- *  Copyright (C) 1991, 1992  Linus Torvalds
- */
-
-/*
- * Hopefully this will be a rather complete VT102 implementation.
- *
- * Beeping thanks to John T Kohl.
- *
- * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
- *   Chars, and VT100 enhancements by Peter MacDonald.
- *
- * Copy and paste function by Andrew Haylett,
- *   some enhancements by Alessandro Rubini.
- *
- * Code to check for different video-cards mostly by Galen Hunt,
- * <g-hunt@ee.utah.edu>
- *
- * Rudimentary ISO 10646/Unicode/UTF-8 character set support by
- * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>.
- *
- * Dynamic allocation of consoles, aeb@cwi.nl, May 1994
- * Resizing of consoles, aeb, 940926
- *
- * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94
- * <poe@daimi.aau.dk>
- *
- * User-defined bell sound, new setterm control sequences and printk
- * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95
- *
- * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp>
- *
- * Merge with the abstract console driver by Geert Uytterhoeven
- * <geert@linux-m68k.org>, Jan 1997.
- *
- *   Original m68k console driver modifications by
- *
- *     - Arno Griffioen <arno@usn.nl>
- *     - David Carter <carter@cs.bris.ac.uk>
- * 
- *   The abstract console driver provides a generic interface for a text
- *   console. It supports VGA text mode, frame buffer based graphical consoles
- *   and special graphics processors that are only accessible through some
- *   registers (e.g. a TMS340x0 GSP).
- *
- *   The interface to the hardware is specified using a special structure
- *   (struct consw) which contains function pointers to console operations
- *   (see <linux/console.h> for more information).
- *
- * Support for changeable cursor shape
- * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>, August 1997
- *
- * Ported to i386 and con_scrolldelta fixed
- * by Emmanuel Marty <core@ggi-project.org>, April 1998
- *
- * Resurrected character buffers in videoram plus lots of other trickery
- * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998
- *
- * Removed old-style timers, introduced console_timer, made timer
- * deletion SMP-safe.  17Jun00, Andrew Morton
- *
- * Removed console_lock, enabled interrupts across all console operations
- * 13 March 2001, Andrew Morton
- *
- * Fixed UTF-8 mode so alternate charset modes always work according
- * to control sequences interpreted in do_con_trol function
- * preserving backward VT100 semigraphics compatibility,
- * malformed UTF sequences represented as sequences of replacement glyphs,
- * original codes or '?' as a last resort if replacement glyph is undefined
- * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/kd.h>
-#include <linux/slab.h>
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/console.h>
-#include <linux/init.h>
-#include <linux/mutex.h>
-#include <linux/vt_kern.h>
-#include <linux/selection.h>
-#include <linux/smp_lock.h>
-#include <linux/tiocl.h>
-#include <linux/kbd_kern.h>
-#include <linux/consolemap.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/pm.h>
-#include <linux/font.h>
-#include <linux/bitops.h>
-#include <linux/notifier.h>
-#include <linux/device.h>
-#include <linux/io.h>
-#include <asm/system.h>
-#include <linux/uaccess.h>
-#include <linux/kdb.h>
-#include <linux/ctype.h>
-
-#define MAX_NR_CON_DRIVER 16
-
-#define CON_DRIVER_FLAG_MODULE 1
-#define CON_DRIVER_FLAG_INIT   2
-#define CON_DRIVER_FLAG_ATTR   4
-
-struct con_driver {
-       const struct consw *con;
-       const char *desc;
-       struct device *dev;
-       int node;
-       int first;
-       int last;
-       int flag;
-};
-
-static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER];
-const struct consw *conswitchp;
-
-/* A bitmap for codes <32. A bit of 1 indicates that the code
- * corresponding to that bit number invokes some special action
- * (such as cursor movement) and should not be displayed as a
- * glyph unless the disp_ctrl mode is explicitly enabled.
- */
-#define CTRL_ACTION 0x0d00ff81
-#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */
-
-/*
- * Here is the default bell parameters: 750HZ, 1/8th of a second
- */
-#define DEFAULT_BELL_PITCH     750
-#define DEFAULT_BELL_DURATION  (HZ/8)
-
-struct vc vc_cons [MAX_NR_CONSOLES];
-
-#ifndef VT_SINGLE_DRIVER
-static const struct consw *con_driver_map[MAX_NR_CONSOLES];
-#endif
-
-static int con_open(struct tty_struct *, struct file *);
-static void vc_init(struct vc_data *vc, unsigned int rows,
-                   unsigned int cols, int do_clear);
-static void gotoxy(struct vc_data *vc, int new_x, int new_y);
-static void save_cur(struct vc_data *vc);
-static void reset_terminal(struct vc_data *vc, int do_clear);
-static void con_flush_chars(struct tty_struct *tty);
-static int set_vesa_blanking(char __user *p);
-static void set_cursor(struct vc_data *vc);
-static void hide_cursor(struct vc_data *vc);
-static void console_callback(struct work_struct *ignored);
-static void blank_screen_t(unsigned long dummy);
-static void set_palette(struct vc_data *vc);
-
-static int printable;          /* Is console ready for printing? */
-int default_utf8 = true;
-module_param(default_utf8, int, S_IRUGO | S_IWUSR);
-int global_cursor_default = -1;
-module_param(global_cursor_default, int, S_IRUGO | S_IWUSR);
-
-static int cur_default = CUR_DEFAULT;
-module_param(cur_default, int, S_IRUGO | S_IWUSR);
-
-/*
- * ignore_poke: don't unblank the screen when things are typed.  This is
- * mainly for the privacy of braille terminal users.
- */
-static int ignore_poke;
-
-int do_poke_blanked_console;
-int console_blanked;
-
-static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
-static int vesa_off_interval;
-static int blankinterval = 10*60;
-core_param(consoleblank, blankinterval, int, 0444);
-
-static DECLARE_WORK(console_work, console_callback);
-
-/*
- * fg_console is the current virtual console,
- * last_console is the last used one,
- * want_console is the console we want to switch to,
- * saved_* variants are for save/restore around kernel debugger enter/leave
- */
-int fg_console;
-int last_console;
-int want_console = -1;
-static int saved_fg_console;
-static int saved_last_console;
-static int saved_want_console;
-static int saved_vc_mode;
-static int saved_console_blanked;
-
-/*
- * For each existing display, we have a pointer to console currently visible
- * on that display, allowing consoles other than fg_console to be refreshed
- * appropriately. Unless the low-level driver supplies its own display_fg
- * variable, we use this one for the "master display".
- */
-static struct vc_data *master_display_fg;
-
-/*
- * Unfortunately, we need to delay tty echo when we're currently writing to the
- * console since the code is (and always was) not re-entrant, so we schedule
- * all flip requests to process context with schedule-task() and run it from
- * console_callback().
- */
-
-/*
- * For the same reason, we defer scrollback to the console callback.
- */
-static int scrollback_delta;
-
-/*
- * Hook so that the power management routines can (un)blank
- * the console on our behalf.
- */
-int (*console_blank_hook)(int);
-
-static DEFINE_TIMER(console_timer, blank_screen_t, 0, 0);
-static int blank_state;
-static int blank_timer_expired;
-enum {
-       blank_off = 0,
-       blank_normal_wait,
-       blank_vesa_wait,
-};
-
-/*
- * Notifier list for console events.
- */
-static ATOMIC_NOTIFIER_HEAD(vt_notifier_list);
-
-int register_vt_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_register(&vt_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(register_vt_notifier);
-
-int unregister_vt_notifier(struct notifier_block *nb)
-{
-       return atomic_notifier_chain_unregister(&vt_notifier_list, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_vt_notifier);
-
-static void notify_write(struct vc_data *vc, unsigned int unicode)
-{
-       struct vt_notifier_param param = { .vc = vc, unicode = unicode };
-       atomic_notifier_call_chain(&vt_notifier_list, VT_WRITE, &param);
-}
-
-static void notify_update(struct vc_data *vc)
-{
-       struct vt_notifier_param param = { .vc = vc };
-       atomic_notifier_call_chain(&vt_notifier_list, VT_UPDATE, &param);
-}
-/*
- *     Low-Level Functions
- */
-
-#define IS_FG(vc)      ((vc)->vc_num == fg_console)
-
-#ifdef VT_BUF_VRAM_ONLY
-#define DO_UPDATE(vc)  0
-#else
-#define DO_UPDATE(vc)  (CON_IS_VISIBLE(vc) && !console_blanked)
-#endif
-
-static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed)
-{
-       unsigned short *p;
-       
-       if (!viewed)
-               p = (unsigned short *)(vc->vc_origin + offset);
-       else if (!vc->vc_sw->con_screen_pos)
-               p = (unsigned short *)(vc->vc_visible_origin + offset);
-       else
-               p = vc->vc_sw->con_screen_pos(vc, offset);
-       return p;
-}
-
-/* Called  from the keyboard irq path.. */
-static inline void scrolldelta(int lines)
-{
-       /* FIXME */
-       /* scrolldelta needs some kind of consistency lock, but the BKL was
-          and still is not protecting versus the scheduled back end */
-       scrollback_delta += lines;
-       schedule_console_callback();
-}
-
-void schedule_console_callback(void)
-{
-       schedule_work(&console_work);
-}
-
-static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
-{
-       unsigned short *d, *s;
-
-       if (t+nr >= b)
-               nr = b - t - 1;
-       if (b > vc->vc_rows || t >= b || nr < 1)
-               return;
-       if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr))
-               return;
-       d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
-       s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
-       scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
-       scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char,
-                   vc->vc_size_row * nr);
-}
-
-static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
-{
-       unsigned short *s;
-       unsigned int step;
-
-       if (t+nr >= b)
-               nr = b - t - 1;
-       if (b > vc->vc_rows || t >= b || nr < 1)
-               return;
-       if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr))
-               return;
-       s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
-       step = vc->vc_cols * nr;
-       scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row);
-       scr_memsetw(s, vc->vc_video_erase_char, 2 * step);
-}
-
-static void do_update_region(struct vc_data *vc, unsigned long start, int count)
-{
-#ifndef VT_BUF_VRAM_ONLY
-       unsigned int xx, yy, offset;
-       u16 *p;
-
-       p = (u16 *) start;
-       if (!vc->vc_sw->con_getxy) {
-               offset = (start - vc->vc_origin) / 2;
-               xx = offset % vc->vc_cols;
-               yy = offset / vc->vc_cols;
-       } else {
-               int nxx, nyy;
-               start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy);
-               xx = nxx; yy = nyy;
-       }
-       for(;;) {
-               u16 attrib = scr_readw(p) & 0xff00;
-               int startx = xx;
-               u16 *q = p;
-               while (xx < vc->vc_cols && count) {
-                       if (attrib != (scr_readw(p) & 0xff00)) {
-                               if (p > q)
-                                       vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
-                               startx = xx;
-                               q = p;
-                               attrib = scr_readw(p) & 0xff00;
-                       }
-                       p++;
-                       xx++;
-                       count--;
-               }
-               if (p > q)
-                       vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
-               if (!count)
-                       break;
-               xx = 0;
-               yy++;
-               if (vc->vc_sw->con_getxy) {
-                       p = (u16 *)start;
-                       start = vc->vc_sw->con_getxy(vc, start, NULL, NULL);
-               }
-       }
-#endif
-}
-
-void update_region(struct vc_data *vc, unsigned long start, int count)
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       if (DO_UPDATE(vc)) {
-               hide_cursor(vc);
-               do_update_region(vc, start, count);
-               set_cursor(vc);
-       }
-}
-
-/* Structure of attributes is hardware-dependent */
-
-static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
-    u8 _underline, u8 _reverse, u8 _italic)
-{
-       if (vc->vc_sw->con_build_attr)
-               return vc->vc_sw->con_build_attr(vc, _color, _intensity,
-                      _blink, _underline, _reverse, _italic);
-
-#ifndef VT_BUF_VRAM_ONLY
-/*
- * ++roman: I completely changed the attribute format for monochrome
- * mode (!can_do_color). The formerly used MDA (monochrome display
- * adapter) format didn't allow the combination of certain effects.
- * Now the attribute is just a bit vector:
- *  Bit 0..1: intensity (0..2)
- *  Bit 2   : underline
- *  Bit 3   : reverse
- *  Bit 7   : blink
- */
-       {
-       u8 a = _color;
-       if (!vc->vc_can_do_color)
-               return _intensity |
-                      (_italic ? 2 : 0) |
-                      (_underline ? 4 : 0) |
-                      (_reverse ? 8 : 0) |
-                      (_blink ? 0x80 : 0);
-       if (_italic)
-               a = (a & 0xF0) | vc->vc_itcolor;
-       else if (_underline)
-               a = (a & 0xf0) | vc->vc_ulcolor;
-       else if (_intensity == 0)
-               a = (a & 0xf0) | vc->vc_ulcolor;
-       if (_reverse)
-               a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
-       if (_blink)
-               a ^= 0x80;
-       if (_intensity == 2)
-               a ^= 0x08;
-       if (vc->vc_hi_font_mask == 0x100)
-               a <<= 1;
-       return a;
-       }
-#else
-       return 0;
-#endif
-}
-
-static void update_attr(struct vc_data *vc)
-{
-       vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity,
-                     vc->vc_blink, vc->vc_underline,
-                     vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
-       vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
-}
-
-/* Note: inverting the screen twice should revert to the original state */
-void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
-{
-       unsigned short *p;
-
-       WARN_CONSOLE_UNLOCKED();
-
-       count /= 2;
-       p = screenpos(vc, offset, viewed);
-       if (vc->vc_sw->con_invert_region)
-               vc->vc_sw->con_invert_region(vc, p, count);
-#ifndef VT_BUF_VRAM_ONLY
-       else {
-               u16 *q = p;
-               int cnt = count;
-               u16 a;
-
-               if (!vc->vc_can_do_color) {
-                       while (cnt--) {
-                           a = scr_readw(q);
-                           a ^= 0x0800;
-                           scr_writew(a, q);
-                           q++;
-                       }
-               } else if (vc->vc_hi_font_mask == 0x100) {
-                       while (cnt--) {
-                               a = scr_readw(q);
-                               a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
-                               scr_writew(a, q);
-                               q++;
-                       }
-               } else {
-                       while (cnt--) {
-                               a = scr_readw(q);
-                               a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
-                               scr_writew(a, q);
-                               q++;
-                       }
-               }
-       }
-#endif
-       if (DO_UPDATE(vc))
-               do_update_region(vc, (unsigned long) p, count);
-}
-
-/* used by selection: complement pointer position */
-void complement_pos(struct vc_data *vc, int offset)
-{
-       static int old_offset = -1;
-       static unsigned short old;
-       static unsigned short oldx, oldy;
-
-       WARN_CONSOLE_UNLOCKED();
-
-       if (old_offset != -1 && old_offset >= 0 &&
-           old_offset < vc->vc_screenbuf_size) {
-               scr_writew(old, screenpos(vc, old_offset, 1));
-               if (DO_UPDATE(vc))
-                       vc->vc_sw->con_putc(vc, old, oldy, oldx);
-       }
-
-       old_offset = offset;
-
-       if (offset != -1 && offset >= 0 &&
-           offset < vc->vc_screenbuf_size) {
-               unsigned short new;
-               unsigned short *p;
-               p = screenpos(vc, offset, 1);
-               old = scr_readw(p);
-               new = old ^ vc->vc_complement_mask;
-               scr_writew(new, p);
-               if (DO_UPDATE(vc)) {
-                       oldx = (offset >> 1) % vc->vc_cols;
-                       oldy = (offset >> 1) / vc->vc_cols;
-                       vc->vc_sw->con_putc(vc, new, oldy, oldx);
-               }
-       }
-
-}
-
-static void insert_char(struct vc_data *vc, unsigned int nr)
-{
-       unsigned short *p, *q = (unsigned short *)vc->vc_pos;
-
-       p = q + vc->vc_cols - nr - vc->vc_x;
-       while (--p >= q)
-               scr_writew(scr_readw(p), p + nr);
-       scr_memsetw(q, vc->vc_video_erase_char, nr * 2);
-       vc->vc_need_wrap = 0;
-       if (DO_UPDATE(vc)) {
-               unsigned short oldattr = vc->vc_attr;
-               vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1,
-                                    vc->vc_cols - vc->vc_x - nr);
-               vc->vc_attr = vc->vc_video_erase_char >> 8;
-               while (nr--)
-                       vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr);
-               vc->vc_attr = oldattr;
-       }
-}
-
-static void delete_char(struct vc_data *vc, unsigned int nr)
-{
-       unsigned int i = vc->vc_x;
-       unsigned short *p = (unsigned short *)vc->vc_pos;
-
-       while (++i <= vc->vc_cols - nr) {
-               scr_writew(scr_readw(p+nr), p);
-               p++;
-       }
-       scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
-       vc->vc_need_wrap = 0;
-       if (DO_UPDATE(vc)) {
-               unsigned short oldattr = vc->vc_attr;
-               vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1,
-                                    vc->vc_cols - vc->vc_x - nr);
-               vc->vc_attr = vc->vc_video_erase_char >> 8;
-               while (nr--)
-                       vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y,
-                                    vc->vc_cols - 1 - nr);
-               vc->vc_attr = oldattr;
-       }
-}
-
-static int softcursor_original;
-
-static void add_softcursor(struct vc_data *vc)
-{
-       int i = scr_readw((u16 *) vc->vc_pos);
-       u32 type = vc->vc_cursor_type;
-
-       if (! (type & 0x10)) return;
-       if (softcursor_original != -1) return;
-       softcursor_original = i;
-       i |= ((type >> 8) & 0xff00 );
-       i ^= ((type) & 0xff00 );
-       if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
-       if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
-       scr_writew(i, (u16 *) vc->vc_pos);
-       if (DO_UPDATE(vc))
-               vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x);
-}
-
-static void hide_softcursor(struct vc_data *vc)
-{
-       if (softcursor_original != -1) {
-               scr_writew(softcursor_original, (u16 *)vc->vc_pos);
-               if (DO_UPDATE(vc))
-                       vc->vc_sw->con_putc(vc, softcursor_original,
-                                       vc->vc_y, vc->vc_x);
-               softcursor_original = -1;
-       }
-}
-
-static void hide_cursor(struct vc_data *vc)
-{
-       if (vc == sel_cons)
-               clear_selection();
-       vc->vc_sw->con_cursor(vc, CM_ERASE);
-       hide_softcursor(vc);
-}
-
-static void set_cursor(struct vc_data *vc)
-{
-       if (!IS_FG(vc) || console_blanked ||
-           vc->vc_mode == KD_GRAPHICS)
-               return;
-       if (vc->vc_deccm) {
-               if (vc == sel_cons)
-                       clear_selection();
-               add_softcursor(vc);
-               if ((vc->vc_cursor_type & 0x0f) != 1)
-                       vc->vc_sw->con_cursor(vc, CM_DRAW);
-       } else
-               hide_cursor(vc);
-}
-
-static void set_origin(struct vc_data *vc)
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       if (!CON_IS_VISIBLE(vc) ||
-           !vc->vc_sw->con_set_origin ||
-           !vc->vc_sw->con_set_origin(vc))
-               vc->vc_origin = (unsigned long)vc->vc_screenbuf;
-       vc->vc_visible_origin = vc->vc_origin;
-       vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
-       vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
-}
-
-static inline void save_screen(struct vc_data *vc)
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       if (vc->vc_sw->con_save_screen)
-               vc->vc_sw->con_save_screen(vc);
-}
-
-/*
- *     Redrawing of screen
- */
-
-static void clear_buffer_attributes(struct vc_data *vc)
-{
-       unsigned short *p = (unsigned short *)vc->vc_origin;
-       int count = vc->vc_screenbuf_size / 2;
-       int mask = vc->vc_hi_font_mask | 0xff;
-
-       for (; count > 0; count--, p++) {
-               scr_writew((scr_readw(p)&mask) | (vc->vc_video_erase_char & ~mask), p);
-       }
-}
-
-void redraw_screen(struct vc_data *vc, int is_switch)
-{
-       int redraw = 0;
-
-       WARN_CONSOLE_UNLOCKED();
-
-       if (!vc) {
-               /* strange ... */
-               /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */
-               return;
-       }
-
-       if (is_switch) {
-               struct vc_data *old_vc = vc_cons[fg_console].d;
-               if (old_vc == vc)
-                       return;
-               if (!CON_IS_VISIBLE(vc))
-                       redraw = 1;
-               *vc->vc_display_fg = vc;
-               fg_console = vc->vc_num;
-               hide_cursor(old_vc);
-               if (!CON_IS_VISIBLE(old_vc)) {
-                       save_screen(old_vc);
-                       set_origin(old_vc);
-               }
-       } else {
-               hide_cursor(vc);
-               redraw = 1;
-       }
-
-       if (redraw) {
-               int update;
-               int old_was_color = vc->vc_can_do_color;
-
-               set_origin(vc);
-               update = vc->vc_sw->con_switch(vc);
-               set_palette(vc);
-               /*
-                * If console changed from mono<->color, the best we can do
-                * is to clear the buffer attributes. As it currently stands,
-                * rebuilding new attributes from the old buffer is not doable
-                * without overly complex code.
-                */
-               if (old_was_color != vc->vc_can_do_color) {
-                       update_attr(vc);
-                       clear_buffer_attributes(vc);
-               }
-
-               /* Forcibly update if we're panicing */
-               if ((update && vc->vc_mode != KD_GRAPHICS) ||
-                   vt_force_oops_output(vc))
-                       do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
-       }
-       set_cursor(vc);
-       if (is_switch) {
-               set_leds();
-               compute_shiftstate();
-               notify_update(vc);
-       }
-}
-
-/*
- *     Allocation, freeing and resizing of VTs.
- */
-
-int vc_cons_allocated(unsigned int i)
-{
-       return (i < MAX_NR_CONSOLES && vc_cons[i].d);
-}
-
-static void visual_init(struct vc_data *vc, int num, int init)
-{
-       /* ++Geert: vc->vc_sw->con_init determines console size */
-       if (vc->vc_sw)
-               module_put(vc->vc_sw->owner);
-       vc->vc_sw = conswitchp;
-#ifndef VT_SINGLE_DRIVER
-       if (con_driver_map[num])
-               vc->vc_sw = con_driver_map[num];
-#endif
-       __module_get(vc->vc_sw->owner);
-       vc->vc_num = num;
-       vc->vc_display_fg = &master_display_fg;
-       vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
-       vc->vc_uni_pagedir = 0;
-       vc->vc_hi_font_mask = 0;
-       vc->vc_complement_mask = 0;
-       vc->vc_can_do_color = 0;
-       vc->vc_panic_force_write = false;
-       vc->vc_sw->con_init(vc, init);
-       if (!vc->vc_complement_mask)
-               vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
-       vc->vc_s_complement_mask = vc->vc_complement_mask;
-       vc->vc_size_row = vc->vc_cols << 1;
-       vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
-}
-
-int vc_allocate(unsigned int currcons) /* return 0 on success */
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       if (currcons >= MAX_NR_CONSOLES)
-               return -ENXIO;
-       if (!vc_cons[currcons].d) {
-           struct vc_data *vc;
-           struct vt_notifier_param param;
-
-           /* prevent users from taking too much memory */
-           if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
-             return -EPERM;
-
-           /* due to the granularity of kmalloc, we waste some memory here */
-           /* the alloc is done in two steps, to optimize the common situation
-              of a 25x80 console (structsize=216, screenbuf_size=4000) */
-           /* although the numbers above are not valid since long ago, the
-              point is still up-to-date and the comment still has its value
-              even if only as a historical artifact.  --mj, July 1998 */
-           param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
-           if (!vc)
-               return -ENOMEM;
-           vc_cons[currcons].d = vc;
-           tty_port_init(&vc->port);
-           INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
-           visual_init(vc, currcons, 1);
-           if (!*vc->vc_uni_pagedir_loc)
-               con_set_default_unimap(vc);
-           vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
-           if (!vc->vc_screenbuf) {
-               kfree(vc);
-               vc_cons[currcons].d = NULL;
-               return -ENOMEM;
-           }
-
-           /* If no drivers have overridden us and the user didn't pass a
-              boot option, default to displaying the cursor */
-           if (global_cursor_default == -1)
-                   global_cursor_default = 1;
-
-           vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
-           vcs_make_sysfs(currcons);
-           atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
-       }
-       return 0;
-}
-
-static inline int resize_screen(struct vc_data *vc, int width, int height,
-                               int user)
-{
-       /* Resizes the resolution of the display adapater */
-       int err = 0;
-
-       if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize)
-               err = vc->vc_sw->con_resize(vc, width, height, user);
-
-       return err;
-}
-
-/*
- * Change # of rows and columns (0 means unchanged/the size of fg_console)
- * [this is to be used together with some user program
- * like resize that changes the hardware videomode]
- */
-#define VC_RESIZE_MAXCOL (32767)
-#define VC_RESIZE_MAXROW (32767)
-
-/**
- *     vc_do_resize    -       resizing method for the tty
- *     @tty: tty being resized
- *     @real_tty: real tty (different to tty if a pty/tty pair)
- *     @vc: virtual console private data
- *     @cols: columns
- *     @lines: lines
- *
- *     Resize a virtual console, clipping according to the actual constraints.
- *     If the caller passes a tty structure then update the termios winsize
- *     information and perform any necessary signal handling.
- *
- *     Caller must hold the console semaphore. Takes the termios mutex and
- *     ctrl_lock of the tty IFF a tty is passed.
- */
-
-static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
-                               unsigned int cols, unsigned int lines)
-{
-       unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
-       unsigned long end;
-       unsigned int old_cols, old_rows, old_row_size, old_screen_size;
-       unsigned int new_cols, new_rows, new_row_size, new_screen_size;
-       unsigned int user;
-       unsigned short *newscreen;
-
-       WARN_CONSOLE_UNLOCKED();
-
-       if (!vc)
-               return -ENXIO;
-
-       user = vc->vc_resize_user;
-       vc->vc_resize_user = 0;
-
-       if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW)
-               return -EINVAL;
-
-       new_cols = (cols ? cols : vc->vc_cols);
-       new_rows = (lines ? lines : vc->vc_rows);
-       new_row_size = new_cols << 1;
-       new_screen_size = new_row_size * new_rows;
-
-       if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
-               return 0;
-
-       newscreen = kmalloc(new_screen_size, GFP_USER);
-       if (!newscreen)
-               return -ENOMEM;
-
-       old_rows = vc->vc_rows;
-       old_cols = vc->vc_cols;
-       old_row_size = vc->vc_size_row;
-       old_screen_size = vc->vc_screenbuf_size;
-
-       err = resize_screen(vc, new_cols, new_rows, user);
-       if (err) {
-               kfree(newscreen);
-               return err;
-       }
-
-       vc->vc_rows = new_rows;
-       vc->vc_cols = new_cols;
-       vc->vc_size_row = new_row_size;
-       vc->vc_screenbuf_size = new_screen_size;
-
-       rlth = min(old_row_size, new_row_size);
-       rrem = new_row_size - rlth;
-       old_origin = vc->vc_origin;
-       new_origin = (long) newscreen;
-       new_scr_end = new_origin + new_screen_size;
-
-       if (vc->vc_y > new_rows) {
-               if (old_rows - vc->vc_y < new_rows) {
-                       /*
-                        * Cursor near the bottom, copy contents from the
-                        * bottom of buffer
-                        */
-                       old_origin += (old_rows - new_rows) * old_row_size;
-               } else {
-                       /*
-                        * Cursor is in no man's land, copy 1/2 screenful
-                        * from the top and bottom of cursor position
-                        */
-                       old_origin += (vc->vc_y - new_rows/2) * old_row_size;
-               }
-       }
-
-       end = old_origin + old_row_size * min(old_rows, new_rows);
-
-       update_attr(vc);
-
-       while (old_origin < end) {
-               scr_memcpyw((unsigned short *) new_origin,
-                           (unsigned short *) old_origin, rlth);
-               if (rrem)
-                       scr_memsetw((void *)(new_origin + rlth),
-                                   vc->vc_video_erase_char, rrem);
-               old_origin += old_row_size;
-               new_origin += new_row_size;
-       }
-       if (new_scr_end > new_origin)
-               scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
-                           new_scr_end - new_origin);
-       kfree(vc->vc_screenbuf);
-       vc->vc_screenbuf = newscreen;
-       vc->vc_screenbuf_size = new_screen_size;
-       set_origin(vc);
-
-       /* do part of a reset_terminal() */
-       vc->vc_top = 0;
-       vc->vc_bottom = vc->vc_rows;
-       gotoxy(vc, vc->vc_x, vc->vc_y);
-       save_cur(vc);
-
-       if (tty) {
-               /* Rewrite the requested winsize data with the actual
-                  resulting sizes */
-               struct winsize ws;
-               memset(&ws, 0, sizeof(ws));
-               ws.ws_row = vc->vc_rows;
-               ws.ws_col = vc->vc_cols;
-               ws.ws_ypixel = vc->vc_scan_lines;
-               tty_do_resize(tty, &ws);
-       }
-
-       if (CON_IS_VISIBLE(vc))
-               update_screen(vc);
-       vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num);
-       return err;
-}
-
-/**
- *     vc_resize               -       resize a VT
- *     @vc: virtual console
- *     @cols: columns
- *     @rows: rows
- *
- *     Resize a virtual console as seen from the console end of things. We
- *     use the common vc_do_resize methods to update the structures. The
- *     caller must hold the console sem to protect console internals and
- *     vc->port.tty
- */
-
-int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
-{
-       return vc_do_resize(vc->port.tty, vc, cols, rows);
-}
-
-/**
- *     vt_resize               -       resize a VT
- *     @tty: tty to resize
- *     @ws: winsize attributes
- *
- *     Resize a virtual terminal. This is called by the tty layer as we
- *     register our own handler for resizing. The mutual helper does all
- *     the actual work.
- *
- *     Takes the console sem and the called methods then take the tty
- *     termios_mutex and the tty ctrl_lock in that order.
- */
-static int vt_resize(struct tty_struct *tty, struct winsize *ws)
-{
-       struct vc_data *vc = tty->driver_data;
-       int ret;
-
-       acquire_console_sem();
-       ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row);
-       release_console_sem();
-       return ret;
-}
-
-void vc_deallocate(unsigned int currcons)
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       if (vc_cons_allocated(currcons)) {
-               struct vc_data *vc = vc_cons[currcons].d;
-               struct vt_notifier_param param = { .vc = vc };
-
-               atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, &param);
-               vcs_remove_sysfs(currcons);
-               vc->vc_sw->con_deinit(vc);
-               put_pid(vc->vt_pid);
-               module_put(vc->vc_sw->owner);
-               kfree(vc->vc_screenbuf);
-               if (currcons >= MIN_NR_CONSOLES)
-                       kfree(vc);
-               vc_cons[currcons].d = NULL;
-       }
-}
-
-/*
- *     VT102 emulator
- */
-
-#define set_kbd(vc, x) set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
-#define clr_kbd(vc, x) clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
-#define is_kbd(vc, x)  vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
-
-#define decarm         VC_REPEAT
-#define decckm         VC_CKMODE
-#define kbdapplic      VC_APPLIC
-#define lnm            VC_CRLF
-
-/*
- * this is what the terminal answers to a ESC-Z or csi0c query.
- */
-#define VT100ID "\033[?1;2c"
-#define VT102ID "\033[?6c"
-
-unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
-                                      8,12,10,14, 9,13,11,15 };
-
-/* the default colour table, for VGA+ colour systems */
-int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
-    0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
-int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
-    0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
-int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
-    0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
-
-module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR);
-module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR);
-module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR);
-
-/*
- * gotoxy() must verify all boundaries, because the arguments
- * might also be negative. If the given position is out of
- * bounds, the cursor is placed at the nearest margin.
- */
-static void gotoxy(struct vc_data *vc, int new_x, int new_y)
-{
-       int min_y, max_y;
-
-       if (new_x < 0)
-               vc->vc_x = 0;
-       else {
-               if (new_x >= vc->vc_cols)
-                       vc->vc_x = vc->vc_cols - 1;
-               else
-                       vc->vc_x = new_x;
-       }
-
-       if (vc->vc_decom) {
-               min_y = vc->vc_top;
-               max_y = vc->vc_bottom;
-       } else {
-               min_y = 0;
-               max_y = vc->vc_rows;
-       }
-       if (new_y < min_y)
-               vc->vc_y = min_y;
-       else if (new_y >= max_y)
-               vc->vc_y = max_y - 1;
-       else
-               vc->vc_y = new_y;
-       vc->vc_pos = vc->vc_origin + vc->vc_y * vc->vc_size_row + (vc->vc_x<<1);
-       vc->vc_need_wrap = 0;
-}
-
-/* for absolute user moves, when decom is set */
-static void gotoxay(struct vc_data *vc, int new_x, int new_y)
-{
-       gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y);
-}
-
-void scrollback(struct vc_data *vc, int lines)
-{
-       if (!lines)
-               lines = vc->vc_rows / 2;
-       scrolldelta(-lines);
-}
-
-void scrollfront(struct vc_data *vc, int lines)
-{
-       if (!lines)
-               lines = vc->vc_rows / 2;
-       scrolldelta(lines);
-}
-
-static void lf(struct vc_data *vc)
-{
-       /* don't scroll if above bottom of scrolling region, or
-        * if below scrolling region
-        */
-       if (vc->vc_y + 1 == vc->vc_bottom)
-               scrup(vc, vc->vc_top, vc->vc_bottom, 1);
-       else if (vc->vc_y < vc->vc_rows - 1) {
-               vc->vc_y++;
-               vc->vc_pos += vc->vc_size_row;
-       }
-       vc->vc_need_wrap = 0;
-       notify_write(vc, '\n');
-}
-
-static void ri(struct vc_data *vc)
-{
-       /* don't scroll if below top of scrolling region, or
-        * if above scrolling region
-        */
-       if (vc->vc_y == vc->vc_top)
-               scrdown(vc, vc->vc_top, vc->vc_bottom, 1);
-       else if (vc->vc_y > 0) {
-               vc->vc_y--;
-               vc->vc_pos -= vc->vc_size_row;
-       }
-       vc->vc_need_wrap = 0;
-}
-
-static inline void cr(struct vc_data *vc)
-{
-       vc->vc_pos -= vc->vc_x << 1;
-       vc->vc_need_wrap = vc->vc_x = 0;
-       notify_write(vc, '\r');
-}
-
-static inline void bs(struct vc_data *vc)
-{
-       if (vc->vc_x) {
-               vc->vc_pos -= 2;
-               vc->vc_x--;
-               vc->vc_need_wrap = 0;
-               notify_write(vc, '\b');
-       }
-}
-
-static inline void del(struct vc_data *vc)
-{
-       /* ignored */
-}
-
-static void csi_J(struct vc_data *vc, int vpar)
-{
-       unsigned int count;
-       unsigned short * start;
-
-       switch (vpar) {
-               case 0: /* erase from cursor to end of display */
-                       count = (vc->vc_scr_end - vc->vc_pos) >> 1;
-                       start = (unsigned short *)vc->vc_pos;
-                       if (DO_UPDATE(vc)) {
-                               /* do in two stages */
-                               vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
-                                             vc->vc_cols - vc->vc_x);
-                               vc->vc_sw->con_clear(vc, vc->vc_y + 1, 0,
-                                             vc->vc_rows - vc->vc_y - 1,
-                                             vc->vc_cols);
-                       }
-                       break;
-               case 1: /* erase from start to cursor */
-                       count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
-                       start = (unsigned short *)vc->vc_origin;
-                       if (DO_UPDATE(vc)) {
-                               /* do in two stages */
-                               vc->vc_sw->con_clear(vc, 0, 0, vc->vc_y,
-                                             vc->vc_cols);
-                               vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
-                                             vc->vc_x + 1);
-                       }
-                       break;
-               case 2: /* erase whole display */
-                       count = vc->vc_cols * vc->vc_rows;
-                       start = (unsigned short *)vc->vc_origin;
-                       if (DO_UPDATE(vc))
-                               vc->vc_sw->con_clear(vc, 0, 0,
-                                             vc->vc_rows,
-                                             vc->vc_cols);
-                       break;
-               default:
-                       return;
-       }
-       scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
-       vc->vc_need_wrap = 0;
-}
-
-static void csi_K(struct vc_data *vc, int vpar)
-{
-       unsigned int count;
-       unsigned short * start;
-
-       switch (vpar) {
-               case 0: /* erase from cursor to end of line */
-                       count = vc->vc_cols - vc->vc_x;
-                       start = (unsigned short *)vc->vc_pos;
-                       if (DO_UPDATE(vc))
-                               vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
-                                                    vc->vc_cols - vc->vc_x);
-                       break;
-               case 1: /* erase from start of line to cursor */
-                       start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
-                       count = vc->vc_x + 1;
-                       if (DO_UPDATE(vc))
-                               vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
-                                                    vc->vc_x + 1);
-                       break;
-               case 2: /* erase whole line */
-                       start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
-                       count = vc->vc_cols;
-                       if (DO_UPDATE(vc))
-                               vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
-                                             vc->vc_cols);
-                       break;
-               default:
-                       return;
-       }
-       scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
-       vc->vc_need_wrap = 0;
-}
-
-static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */
-{                                        /* not vt100? */
-       int count;
-
-       if (!vpar)
-               vpar++;
-       count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar;
-
-       scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count);
-       if (DO_UPDATE(vc))
-               vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count);
-       vc->vc_need_wrap = 0;
-}
-
-static void default_attr(struct vc_data *vc)
-{
-       vc->vc_intensity = 1;
-       vc->vc_italic = 0;
-       vc->vc_underline = 0;
-       vc->vc_reverse = 0;
-       vc->vc_blink = 0;
-       vc->vc_color = vc->vc_def_color;
-}
-
-/* console_sem is held */
-static void csi_m(struct vc_data *vc)
-{
-       int i;
-
-       for (i = 0; i <= vc->vc_npar; i++)
-               switch (vc->vc_par[i]) {
-                       case 0: /* all attributes off */
-                               default_attr(vc);
-                               break;
-                       case 1:
-                               vc->vc_intensity = 2;
-                               break;
-                       case 2:
-                               vc->vc_intensity = 0;
-                               break;
-                       case 3:
-                               vc->vc_italic = 1;
-                               break;
-                       case 4:
-                               vc->vc_underline = 1;
-                               break;
-                       case 5:
-                               vc->vc_blink = 1;
-                               break;
-                       case 7:
-                               vc->vc_reverse = 1;
-                               break;
-                       case 10: /* ANSI X3.64-1979 (SCO-ish?)
-                                 * Select primary font, don't display
-                                 * control chars if defined, don't set
-                                 * bit 8 on output.
-                                 */
-                               vc->vc_translate = set_translate(vc->vc_charset == 0
-                                               ? vc->vc_G0_charset
-                                               : vc->vc_G1_charset, vc);
-                               vc->vc_disp_ctrl = 0;
-                               vc->vc_toggle_meta = 0;
-                               break;
-                       case 11: /* ANSI X3.64-1979 (SCO-ish?)
-                                 * Select first alternate font, lets
-                                 * chars < 32 be displayed as ROM chars.
-                                 */
-                               vc->vc_translate = set_translate(IBMPC_MAP, vc);
-                               vc->vc_disp_ctrl = 1;
-                               vc->vc_toggle_meta = 0;
-                               break;
-                       case 12: /* ANSI X3.64-1979 (SCO-ish?)
-                                 * Select second alternate font, toggle
-                                 * high bit before displaying as ROM char.
-                                 */
-                               vc->vc_translate = set_translate(IBMPC_MAP, vc);
-                               vc->vc_disp_ctrl = 1;
-                               vc->vc_toggle_meta = 1;
-                               break;
-                       case 21:
-                       case 22:
-                               vc->vc_intensity = 1;
-                               break;
-                       case 23:
-                               vc->vc_italic = 0;
-                               break;
-                       case 24:
-                               vc->vc_underline = 0;
-                               break;
-                       case 25:
-                               vc->vc_blink = 0;
-                               break;
-                       case 27:
-                               vc->vc_reverse = 0;
-                               break;
-                       case 38: /* ANSI X3.64-1979 (SCO-ish?)
-                                 * Enables underscore, white foreground
-                                 * with white underscore (Linux - use
-                                 * default foreground).
-                                 */
-                               vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
-                               vc->vc_underline = 1;
-                               break;
-                       case 39: /* ANSI X3.64-1979 (SCO-ish?)
-                                 * Disable underline option.
-                                 * Reset colour to default? It did this
-                                 * before...
-                                 */
-                               vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
-                               vc->vc_underline = 0;
-                               break;
-                       case 49:
-                               vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f);
-                               break;
-                       default:
-                               if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
-                                       vc->vc_color = color_table[vc->vc_par[i] - 30]
-                                               | (vc->vc_color & 0xf0);
-                               else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47)
-                                       vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4)
-                                               | (vc->vc_color & 0x0f);
-                               break;
-               }
-       update_attr(vc);
-}
-
-static void respond_string(const char *p, struct tty_struct *tty)
-{
-       while (*p) {
-               tty_insert_flip_char(tty, *p, 0);
-               p++;
-       }
-       con_schedule_flip(tty);
-}
-
-static void cursor_report(struct vc_data *vc, struct tty_struct *tty)
-{
-       char buf[40];
-
-       sprintf(buf, "\033[%d;%dR", vc->vc_y + (vc->vc_decom ? vc->vc_top + 1 : 1), vc->vc_x + 1);
-       respond_string(buf, tty);
-}
-
-static inline void status_report(struct tty_struct *tty)
-{
-       respond_string("\033[0n", tty); /* Terminal ok */
-}
-
-static inline void respond_ID(struct tty_struct * tty)
-{
-       respond_string(VT102ID, tty);
-}
-
-void mouse_report(struct tty_struct *tty, int butt, int mrx, int mry)
-{
-       char buf[8];
-
-       sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
-               (char)('!' + mry));
-       respond_string(buf, tty);
-}
-
-/* invoked via ioctl(TIOCLINUX) and through set_selection */
-int mouse_reporting(void)
-{
-       return vc_cons[fg_console].d->vc_report_mouse;
-}
-
-/* console_sem is held */
-static void set_mode(struct vc_data *vc, int on_off)
-{
-       int i;
-
-       for (i = 0; i <= vc->vc_npar; i++)
-               if (vc->vc_ques) {
-                       switch(vc->vc_par[i]) { /* DEC private modes set/reset */
-                       case 1:                 /* Cursor keys send ^[Ox/^[[x */
-                               if (on_off)
-                                       set_kbd(vc, decckm);
-                               else
-                                       clr_kbd(vc, decckm);
-                               break;
-                       case 3: /* 80/132 mode switch unimplemented */
-                               vc->vc_deccolm = on_off;
-#if 0
-                               vc_resize(deccolm ? 132 : 80, vc->vc_rows);
-                               /* this alone does not suffice; some user mode
-                                  utility has to change the hardware regs */
-#endif
-                               break;
-                       case 5:                 /* Inverted screen on/off */
-                               if (vc->vc_decscnm != on_off) {
-                                       vc->vc_decscnm = on_off;
-                                       invert_screen(vc, 0, vc->vc_screenbuf_size, 0);
-                                       update_attr(vc);
-                               }
-                               break;
-                       case 6:                 /* Origin relative/absolute */
-                               vc->vc_decom = on_off;
-                               gotoxay(vc, 0, 0);
-                               break;
-                       case 7:                 /* Autowrap on/off */
-                               vc->vc_decawm = on_off;
-                               break;
-                       case 8:                 /* Autorepeat on/off */
-                               if (on_off)
-                                       set_kbd(vc, decarm);
-                               else
-                                       clr_kbd(vc, decarm);
-                               break;
-                       case 9:
-                               vc->vc_report_mouse = on_off ? 1 : 0;
-                               break;
-                       case 25:                /* Cursor on/off */
-                               vc->vc_deccm = on_off;
-                               break;
-                       case 1000:
-                               vc->vc_report_mouse = on_off ? 2 : 0;
-                               break;
-                       }
-               } else {
-                       switch(vc->vc_par[i]) { /* ANSI modes set/reset */
-                       case 3:                 /* Monitor (display ctrls) */
-                               vc->vc_disp_ctrl = on_off;
-                               break;
-                       case 4:                 /* Insert Mode on/off */
-                               vc->vc_decim = on_off;
-                               break;
-                       case 20:                /* Lf, Enter == CrLf/Lf */
-                               if (on_off)
-                                       set_kbd(vc, lnm);
-                               else
-                                       clr_kbd(vc, lnm);
-                               break;
-                       }
-               }
-}
-
-/* console_sem is held */
-static void setterm_command(struct vc_data *vc)
-{
-       switch(vc->vc_par[0]) {
-               case 1: /* set color for underline mode */
-                       if (vc->vc_can_do_color &&
-                                       vc->vc_par[1] < 16) {
-                               vc->vc_ulcolor = color_table[vc->vc_par[1]];
-                               if (vc->vc_underline)
-                                       update_attr(vc);
-                       }
-                       break;
-               case 2: /* set color for half intensity mode */
-                       if (vc->vc_can_do_color &&
-                                       vc->vc_par[1] < 16) {
-                               vc->vc_halfcolor = color_table[vc->vc_par[1]];
-                               if (vc->vc_intensity == 0)
-                                       update_attr(vc);
-                       }
-                       break;
-               case 8: /* store colors as defaults */
-                       vc->vc_def_color = vc->vc_attr;
-                       if (vc->vc_hi_font_mask == 0x100)
-                               vc->vc_def_color >>= 1;
-                       default_attr(vc);
-                       update_attr(vc);
-                       break;
-               case 9: /* set blanking interval */
-                       blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60;
-                       poke_blanked_console();
-                       break;
-               case 10: /* set bell frequency in Hz */
-                       if (vc->vc_npar >= 1)
-                               vc->vc_bell_pitch = vc->vc_par[1];
-                       else
-                               vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
-                       break;
-               case 11: /* set bell duration in msec */
-                       if (vc->vc_npar >= 1)
-                               vc->vc_bell_duration = (vc->vc_par[1] < 2000) ?
-                                       vc->vc_par[1] * HZ / 1000 : 0;
-                       else
-                               vc->vc_bell_duration = DEFAULT_BELL_DURATION;
-                       break;
-               case 12: /* bring specified console to the front */
-                       if (vc->vc_par[1] >= 1 && vc_cons_allocated(vc->vc_par[1] - 1))
-                               set_console(vc->vc_par[1] - 1);
-                       break;
-               case 13: /* unblank the screen */
-                       poke_blanked_console();
-                       break;
-               case 14: /* set vesa powerdown interval */
-                       vesa_off_interval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ;
-                       break;
-               case 15: /* activate the previous console */
-                       set_console(last_console);
-                       break;
-       }
-}
-
-/* console_sem is held */
-static void csi_at(struct vc_data *vc, unsigned int nr)
-{
-       if (nr > vc->vc_cols - vc->vc_x)
-               nr = vc->vc_cols - vc->vc_x;
-       else if (!nr)
-               nr = 1;
-       insert_char(vc, nr);
-}
-
-/* console_sem is held */
-static void csi_L(struct vc_data *vc, unsigned int nr)
-{
-       if (nr > vc->vc_rows - vc->vc_y)
-               nr = vc->vc_rows - vc->vc_y;
-       else if (!nr)
-               nr = 1;
-       scrdown(vc, vc->vc_y, vc->vc_bottom, nr);
-       vc->vc_need_wrap = 0;
-}
-
-/* console_sem is held */
-static void csi_P(struct vc_data *vc, unsigned int nr)
-{
-       if (nr > vc->vc_cols - vc->vc_x)
-               nr = vc->vc_cols - vc->vc_x;
-       else if (!nr)
-               nr = 1;
-       delete_char(vc, nr);
-}
-
-/* console_sem is held */
-static void csi_M(struct vc_data *vc, unsigned int nr)
-{
-       if (nr > vc->vc_rows - vc->vc_y)
-               nr = vc->vc_rows - vc->vc_y;
-       else if (!nr)
-               nr=1;
-       scrup(vc, vc->vc_y, vc->vc_bottom, nr);
-       vc->vc_need_wrap = 0;
-}
-
-/* console_sem is held (except via vc_init->reset_terminal */
-static void save_cur(struct vc_data *vc)
-{
-       vc->vc_saved_x          = vc->vc_x;
-       vc->vc_saved_y          = vc->vc_y;
-       vc->vc_s_intensity      = vc->vc_intensity;
-       vc->vc_s_italic         = vc->vc_italic;
-       vc->vc_s_underline      = vc->vc_underline;
-       vc->vc_s_blink          = vc->vc_blink;
-       vc->vc_s_reverse        = vc->vc_reverse;
-       vc->vc_s_charset        = vc->vc_charset;
-       vc->vc_s_color          = vc->vc_color;
-       vc->vc_saved_G0         = vc->vc_G0_charset;
-       vc->vc_saved_G1         = vc->vc_G1_charset;
-}
-
-/* console_sem is held */
-static void restore_cur(struct vc_data *vc)
-{
-       gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y);
-       vc->vc_intensity        = vc->vc_s_intensity;
-       vc->vc_italic           = vc->vc_s_italic;
-       vc->vc_underline        = vc->vc_s_underline;
-       vc->vc_blink            = vc->vc_s_blink;
-       vc->vc_reverse          = vc->vc_s_reverse;
-       vc->vc_charset          = vc->vc_s_charset;
-       vc->vc_color            = vc->vc_s_color;
-       vc->vc_G0_charset       = vc->vc_saved_G0;
-       vc->vc_G1_charset       = vc->vc_saved_G1;
-       vc->vc_translate        = set_translate(vc->vc_charset ? vc->vc_G1_charset : vc->vc_G0_charset, vc);
-       update_attr(vc);
-       vc->vc_need_wrap = 0;
-}
-
-enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
-       EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
-       ESpalette };
-
-/* console_sem is held (except via vc_init()) */
-static void reset_terminal(struct vc_data *vc, int do_clear)
-{
-       vc->vc_top              = 0;
-       vc->vc_bottom           = vc->vc_rows;
-       vc->vc_state            = ESnormal;
-       vc->vc_ques             = 0;
-       vc->vc_translate        = set_translate(LAT1_MAP, vc);
-       vc->vc_G0_charset       = LAT1_MAP;
-       vc->vc_G1_charset       = GRAF_MAP;
-       vc->vc_charset          = 0;
-       vc->vc_need_wrap        = 0;
-       vc->vc_report_mouse     = 0;
-       vc->vc_utf              = default_utf8;
-       vc->vc_utf_count        = 0;
-
-       vc->vc_disp_ctrl        = 0;
-       vc->vc_toggle_meta      = 0;
-
-       vc->vc_decscnm          = 0;
-       vc->vc_decom            = 0;
-       vc->vc_decawm           = 1;
-       vc->vc_deccm            = global_cursor_default;
-       vc->vc_decim            = 0;
-
-       set_kbd(vc, decarm);
-       clr_kbd(vc, decckm);
-       clr_kbd(vc, kbdapplic);
-       clr_kbd(vc, lnm);
-       kbd_table[vc->vc_num].lockstate = 0;
-       kbd_table[vc->vc_num].slockstate = 0;
-       kbd_table[vc->vc_num].ledmode = LED_SHOW_FLAGS;
-       kbd_table[vc->vc_num].ledflagstate = kbd_table[vc->vc_num].default_ledflagstate;
-       /* do not do set_leds here because this causes an endless tasklet loop
-          when the keyboard hasn't been initialized yet */
-
-       vc->vc_cursor_type = cur_default;
-       vc->vc_complement_mask = vc->vc_s_complement_mask;
-
-       default_attr(vc);
-       update_attr(vc);
-
-       vc->vc_tab_stop[0]      = 0x01010100;
-       vc->vc_tab_stop[1]      =
-       vc->vc_tab_stop[2]      =
-       vc->vc_tab_stop[3]      =
-       vc->vc_tab_stop[4]      =
-       vc->vc_tab_stop[5]      =
-       vc->vc_tab_stop[6]      =
-       vc->vc_tab_stop[7]      = 0x01010101;
-
-       vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
-       vc->vc_bell_duration = DEFAULT_BELL_DURATION;
-
-       gotoxy(vc, 0, 0);
-       save_cur(vc);
-       if (do_clear)
-           csi_J(vc, 2);
-}
-
-/* console_sem is held */
-static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
-{
-       /*
-        *  Control characters can be used in the _middle_
-        *  of an escape sequence.
-        */
-       switch (c) {
-       case 0:
-               return;
-       case 7:
-               if (vc->vc_bell_duration)
-                       kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration);
-               return;
-       case 8:
-               bs(vc);
-               return;
-       case 9:
-               vc->vc_pos -= (vc->vc_x << 1);
-               while (vc->vc_x < vc->vc_cols - 1) {
-                       vc->vc_x++;
-                       if (vc->vc_tab_stop[vc->vc_x >> 5] & (1 << (vc->vc_x & 31)))
-                               break;
-               }
-               vc->vc_pos += (vc->vc_x << 1);
-               notify_write(vc, '\t');
-               return;
-       case 10: case 11: case 12:
-               lf(vc);
-               if (!is_kbd(vc, lnm))
-                       return;
-       case 13:
-               cr(vc);
-               return;
-       case 14:
-               vc->vc_charset = 1;
-               vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
-               vc->vc_disp_ctrl = 1;
-               return;
-       case 15:
-               vc->vc_charset = 0;
-               vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
-               vc->vc_disp_ctrl = 0;
-               return;
-       case 24: case 26:
-               vc->vc_state = ESnormal;
-               return;
-       case 27:
-               vc->vc_state = ESesc;
-               return;
-       case 127:
-               del(vc);
-               return;
-       case 128+27:
-               vc->vc_state = ESsquare;
-               return;
-       }
-       switch(vc->vc_state) {
-       case ESesc:
-               vc->vc_state = ESnormal;
-               switch (c) {
-               case '[':
-                       vc->vc_state = ESsquare;
-                       return;
-               case ']':
-                       vc->vc_state = ESnonstd;
-                       return;
-               case '%':
-                       vc->vc_state = ESpercent;
-                       return;
-               case 'E':
-                       cr(vc);
-                       lf(vc);
-                       return;
-               case 'M':
-                       ri(vc);
-                       return;
-               case 'D':
-                       lf(vc);
-                       return;
-               case 'H':
-                       vc->vc_tab_stop[vc->vc_x >> 5] |= (1 << (vc->vc_x & 31));
-                       return;
-               case 'Z':
-                       respond_ID(tty);
-                       return;
-               case '7':
-                       save_cur(vc);
-                       return;
-               case '8':
-                       restore_cur(vc);
-                       return;
-               case '(':
-                       vc->vc_state = ESsetG0;
-                       return;
-               case ')':
-                       vc->vc_state = ESsetG1;
-                       return;
-               case '#':
-                       vc->vc_state = EShash;
-                       return;
-               case 'c':
-                       reset_terminal(vc, 1);
-                       return;
-               case '>':  /* Numeric keypad */
-                       clr_kbd(vc, kbdapplic);
-                       return;
-               case '=':  /* Appl. keypad */
-                       set_kbd(vc, kbdapplic);
-                       return;
-               }
-               return;
-       case ESnonstd:
-               if (c=='P') {   /* palette escape sequence */
-                       for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
-                               vc->vc_par[vc->vc_npar] = 0;
-                       vc->vc_npar = 0;
-                       vc->vc_state = ESpalette;
-                       return;
-               } else if (c=='R') {   /* reset palette */
-                       reset_palette(vc);
-                       vc->vc_state = ESnormal;
-               } else
-                       vc->vc_state = ESnormal;
-               return;
-       case ESpalette:
-               if (isxdigit(c)) {
-                       vc->vc_par[vc->vc_npar++] = hex_to_bin(c);
-                       if (vc->vc_npar == 7) {
-                               int i = vc->vc_par[0] * 3, j = 1;
-                               vc->vc_palette[i] = 16 * vc->vc_par[j++];
-                               vc->vc_palette[i++] += vc->vc_par[j++];
-                               vc->vc_palette[i] = 16 * vc->vc_par[j++];
-                               vc->vc_palette[i++] += vc->vc_par[j++];
-                               vc->vc_palette[i] = 16 * vc->vc_par[j++];
-                               vc->vc_palette[i] += vc->vc_par[j];
-                               set_palette(vc);
-                               vc->vc_state = ESnormal;
-                       }
-               } else
-                       vc->vc_state = ESnormal;
-               return;
-       case ESsquare:
-               for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
-                       vc->vc_par[vc->vc_npar] = 0;
-               vc->vc_npar = 0;
-               vc->vc_state = ESgetpars;
-               if (c == '[') { /* Function key */
-                       vc->vc_state=ESfunckey;
-                       return;
-               }
-               vc->vc_ques = (c == '?');
-               if (vc->vc_ques)
-                       return;
-       case ESgetpars:
-               if (c == ';' && vc->vc_npar < NPAR - 1) {
-                       vc->vc_npar++;
-                       return;
-               } else if (c>='0' && c<='9') {
-                       vc->vc_par[vc->vc_npar] *= 10;
-                       vc->vc_par[vc->vc_npar] += c - '0';
-                       return;
-               } else
-                       vc->vc_state = ESgotpars;
-       case ESgotpars:
-               vc->vc_state = ESnormal;
-               switch(c) {
-               case 'h':
-                       set_mode(vc, 1);
-                       return;
-               case 'l':
-                       set_mode(vc, 0);
-                       return;
-               case 'c':
-                       if (vc->vc_ques) {
-                               if (vc->vc_par[0])
-                                       vc->vc_cursor_type = vc->vc_par[0] | (vc->vc_par[1] << 8) | (vc->vc_par[2] << 16);
-                               else
-                                       vc->vc_cursor_type = cur_default;
-                               return;
-                       }
-                       break;
-               case 'm':
-                       if (vc->vc_ques) {
-                               clear_selection();
-                               if (vc->vc_par[0])
-                                       vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1];
-                               else
-                                       vc->vc_complement_mask = vc->vc_s_complement_mask;
-                               return;
-                       }
-                       break;
-               case 'n':
-                       if (!vc->vc_ques) {
-                               if (vc->vc_par[0] == 5)
-                                       status_report(tty);
-                               else if (vc->vc_par[0] == 6)
-                                       cursor_report(vc, tty);
-                       }
-                       return;
-               }
-               if (vc->vc_ques) {
-                       vc->vc_ques = 0;
-                       return;
-               }
-               switch(c) {
-               case 'G': case '`':
-                       if (vc->vc_par[0])
-                               vc->vc_par[0]--;
-                       gotoxy(vc, vc->vc_par[0], vc->vc_y);
-                       return;
-               case 'A':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, vc->vc_x, vc->vc_y - vc->vc_par[0]);
-                       return;
-               case 'B': case 'e':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, vc->vc_x, vc->vc_y + vc->vc_par[0]);
-                       return;
-               case 'C': case 'a':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, vc->vc_x + vc->vc_par[0], vc->vc_y);
-                       return;
-               case 'D':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, vc->vc_x - vc->vc_par[0], vc->vc_y);
-                       return;
-               case 'E':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, 0, vc->vc_y + vc->vc_par[0]);
-                       return;
-               case 'F':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       gotoxy(vc, 0, vc->vc_y - vc->vc_par[0]);
-                       return;
-               case 'd':
-                       if (vc->vc_par[0])
-                               vc->vc_par[0]--;
-                       gotoxay(vc, vc->vc_x ,vc->vc_par[0]);
-                       return;
-               case 'H': case 'f':
-                       if (vc->vc_par[0])
-                               vc->vc_par[0]--;
-                       if (vc->vc_par[1])
-                               vc->vc_par[1]--;
-                       gotoxay(vc, vc->vc_par[1], vc->vc_par[0]);
-                       return;
-               case 'J':
-                       csi_J(vc, vc->vc_par[0]);
-                       return;
-               case 'K':
-                       csi_K(vc, vc->vc_par[0]);
-                       return;
-               case 'L':
-                       csi_L(vc, vc->vc_par[0]);
-                       return;
-               case 'M':
-                       csi_M(vc, vc->vc_par[0]);
-                       return;
-               case 'P':
-                       csi_P(vc, vc->vc_par[0]);
-                       return;
-               case 'c':
-                       if (!vc->vc_par[0])
-                               respond_ID(tty);
-                       return;
-               case 'g':
-                       if (!vc->vc_par[0])
-                               vc->vc_tab_stop[vc->vc_x >> 5] &= ~(1 << (vc->vc_x & 31));
-                       else if (vc->vc_par[0] == 3) {
-                               vc->vc_tab_stop[0] =
-                                       vc->vc_tab_stop[1] =
-                                       vc->vc_tab_stop[2] =
-                                       vc->vc_tab_stop[3] =
-                                       vc->vc_tab_stop[4] =
-                                       vc->vc_tab_stop[5] =
-                                       vc->vc_tab_stop[6] =
-                                       vc->vc_tab_stop[7] = 0;
-                       }
-                       return;
-               case 'm':
-                       csi_m(vc);
-                       return;
-               case 'q': /* DECLL - but only 3 leds */
-                       /* map 0,1,2,3 to 0,1,2,4 */
-                       if (vc->vc_par[0] < 4)
-                               setledstate(kbd_table + vc->vc_num,
-                                           (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4);
-                       return;
-               case 'r':
-                       if (!vc->vc_par[0])
-                               vc->vc_par[0]++;
-                       if (!vc->vc_par[1])
-                               vc->vc_par[1] = vc->vc_rows;
-                       /* Minimum allowed region is 2 lines */
-                       if (vc->vc_par[0] < vc->vc_par[1] &&
-                           vc->vc_par[1] <= vc->vc_rows) {
-                               vc->vc_top = vc->vc_par[0] - 1;
-                               vc->vc_bottom = vc->vc_par[1];
-                               gotoxay(vc, 0, 0);
-                       }
-                       return;
-               case 's':
-                       save_cur(vc);
-                       return;
-               case 'u':
-                       restore_cur(vc);
-                       return;
-               case 'X':
-                       csi_X(vc, vc->vc_par[0]);
-                       return;
-               case '@':
-                       csi_at(vc, vc->vc_par[0]);
-                       return;
-               case ']': /* setterm functions */
-                       setterm_command(vc);
-                       return;
-               }
-               return;
-       case ESpercent:
-               vc->vc_state = ESnormal;
-               switch (c) {
-               case '@':  /* defined in ISO 2022 */
-                       vc->vc_utf = 0;
-                       return;
-               case 'G':  /* prelim official escape code */
-               case '8':  /* retained for compatibility */
-                       vc->vc_utf = 1;
-                       return;
-               }
-               return;
-       case ESfunckey:
-               vc->vc_state = ESnormal;
-               return;
-       case EShash:
-               vc->vc_state = ESnormal;
-               if (c == '8') {
-                       /* DEC screen alignment test. kludge :-) */
-                       vc->vc_video_erase_char =
-                               (vc->vc_video_erase_char & 0xff00) | 'E';
-                       csi_J(vc, 2);
-                       vc->vc_video_erase_char =
-                               (vc->vc_video_erase_char & 0xff00) | ' ';
-                       do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
-               }
-               return;
-       case ESsetG0:
-               if (c == '0')
-                       vc->vc_G0_charset = GRAF_MAP;
-               else if (c == 'B')
-                       vc->vc_G0_charset = LAT1_MAP;
-               else if (c == 'U')
-                       vc->vc_G0_charset = IBMPC_MAP;
-               else if (c == 'K')
-                       vc->vc_G0_charset = USER_MAP;
-               if (vc->vc_charset == 0)
-                       vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
-               vc->vc_state = ESnormal;
-               return;
-       case ESsetG1:
-               if (c == '0')
-                       vc->vc_G1_charset = GRAF_MAP;
-               else if (c == 'B')
-                       vc->vc_G1_charset = LAT1_MAP;
-               else if (c == 'U')
-                       vc->vc_G1_charset = IBMPC_MAP;
-               else if (c == 'K')
-                       vc->vc_G1_charset = USER_MAP;
-               if (vc->vc_charset == 1)
-                       vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
-               vc->vc_state = ESnormal;
-               return;
-       default:
-               vc->vc_state = ESnormal;
-       }
-}
-
-/* This is a temporary buffer used to prepare a tty console write
- * so that we can easily avoid touching user space while holding the
- * console spinlock.  It is allocated in con_init and is shared by
- * this code and the vc_screen read/write tty calls.
- *
- * We have to allocate this statically in the kernel data section
- * since console_init (and thus con_init) are called before any
- * kernel memory allocation is available.
- */
-char con_buf[CON_BUF_SIZE];
-DEFINE_MUTEX(con_buf_mtx);
-
-/* is_double_width() is based on the wcwidth() implementation by
- * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
- * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
- */
-struct interval {
-       uint32_t first;
-       uint32_t last;
-};
-
-static int bisearch(uint32_t ucs, const struct interval *table, int max)
-{
-       int min = 0;
-       int mid;
-
-       if (ucs < table[0].first || ucs > table[max].last)
-               return 0;
-       while (max >= min) {
-               mid = (min + max) / 2;
-               if (ucs > table[mid].last)
-                       min = mid + 1;
-               else if (ucs < table[mid].first)
-                       max = mid - 1;
-               else
-                       return 1;
-       }
-       return 0;
-}
-
-static int is_double_width(uint32_t ucs)
-{
-       static const struct interval double_width[] = {
-               { 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E },
-               { 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF },
-               { 0xFE10, 0xFE19 }, { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 },
-               { 0xFFE0, 0xFFE6 }, { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD }
-       };
-       return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1);
-}
-
-/* acquires console_sem */
-static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
-{
-#ifdef VT_BUF_VRAM_ONLY
-#define FLUSH do { } while(0);
-#else
-#define FLUSH if (draw_x >= 0) { \
-       vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, draw_x); \
-       draw_x = -1; \
-       }
-#endif
-
-       int c, tc, ok, n = 0, draw_x = -1;
-       unsigned int currcons;
-       unsigned long draw_from = 0, draw_to = 0;
-       struct vc_data *vc;
-       unsigned char vc_attr;
-       struct vt_notifier_param param;
-       uint8_t rescan;
-       uint8_t inverse;
-       uint8_t width;
-       u16 himask, charmask;
-
-       if (in_interrupt())
-               return count;
-
-       might_sleep();
-
-       acquire_console_sem();
-       vc = tty->driver_data;
-       if (vc == NULL) {
-               printk(KERN_ERR "vt: argh, driver_data is NULL !\n");
-               release_console_sem();
-               return 0;
-       }
-
-       currcons = vc->vc_num;
-       if (!vc_cons_allocated(currcons)) {
-           /* could this happen? */
-               printk_once("con_write: tty %d not allocated\n", currcons+1);
-           release_console_sem();
-           return 0;
-       }
-
-       himask = vc->vc_hi_font_mask;
-       charmask = himask ? 0x1ff : 0xff;
-
-       /* undraw cursor first */
-       if (IS_FG(vc))
-               hide_cursor(vc);
-
-       param.vc = vc;
-
-       while (!tty->stopped && count) {
-               int orig = *buf;
-               c = orig;
-               buf++;
-               n++;
-               count--;
-               rescan = 0;
-               inverse = 0;
-               width = 1;
-
-               /* Do no translation at all in control states */
-               if (vc->vc_state != ESnormal) {
-                       tc = c;
-               } else if (vc->vc_utf && !vc->vc_disp_ctrl) {
-                   /* Combine UTF-8 into Unicode in vc_utf_char.
-                    * vc_utf_count is the number of continuation bytes still
-                    * expected to arrive.
-                    * vc_npar is the number of continuation bytes arrived so
-                    * far
-                    */
-rescan_last_byte:
-                   if ((c & 0xc0) == 0x80) {
-                       /* Continuation byte received */
-                       static const uint32_t utf8_length_changes[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff };
-                       if (vc->vc_utf_count) {
-                           vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
-                           vc->vc_npar++;
-                           if (--vc->vc_utf_count) {
-                               /* Still need some bytes */
-                               continue;
-                           }
-                           /* Got a whole character */
-                           c = vc->vc_utf_char;
-                           /* Reject overlong sequences */
-                           if (c <= utf8_length_changes[vc->vc_npar - 1] ||
-                                       c > utf8_length_changes[vc->vc_npar])
-                               c = 0xfffd;
-                       } else {
-                           /* Unexpected continuation byte */
-                           vc->vc_utf_count = 0;
-                           c = 0xfffd;
-                       }
-                   } else {
-                       /* Single ASCII byte or first byte of a sequence received */
-                       if (vc->vc_utf_count) {
-                           /* Continuation byte expected */
-                           rescan = 1;
-                           vc->vc_utf_count = 0;
-                           c = 0xfffd;
-                       } else if (c > 0x7f) {
-                           /* First byte of a multibyte sequence received */
-                           vc->vc_npar = 0;
-                           if ((c & 0xe0) == 0xc0) {
-                               vc->vc_utf_count = 1;
-                               vc->vc_utf_char = (c & 0x1f);
-                           } else if ((c & 0xf0) == 0xe0) {
-                               vc->vc_utf_count = 2;
-                               vc->vc_utf_char = (c & 0x0f);
-                           } else if ((c & 0xf8) == 0xf0) {
-                               vc->vc_utf_count = 3;
-                               vc->vc_utf_char = (c & 0x07);
-                           } else if ((c & 0xfc) == 0xf8) {
-                               vc->vc_utf_count = 4;
-                               vc->vc_utf_char = (c & 0x03);
-                           } else if ((c & 0xfe) == 0xfc) {
-                               vc->vc_utf_count = 5;
-                               vc->vc_utf_char = (c & 0x01);
-                           } else {
-                               /* 254 and 255 are invalid */
-                               c = 0xfffd;
-                           }
-                           if (vc->vc_utf_count) {
-                               /* Still need some bytes */
-                               continue;
-                           }
-                       }
-                       /* Nothing to do if an ASCII byte was received */
-                   }
-                   /* End of UTF-8 decoding. */
-                   /* c is the received character, or U+FFFD for invalid sequences. */
-                   /* Replace invalid Unicode code points with U+FFFD too */
-                   if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff)
-                       c = 0xfffd;
-                   tc = c;
-               } else {        /* no utf or alternate charset mode */
-                   tc = vc_translate(vc, c);
-               }
-
-               param.c = tc;
-               if (atomic_notifier_call_chain(&vt_notifier_list, VT_PREWRITE,
-                                       &param) == NOTIFY_STOP)
-                       continue;
-
-                /* If the original code was a control character we
-                 * only allow a glyph to be displayed if the code is
-                 * not normally used (such as for cursor movement) or
-                 * if the disp_ctrl mode has been explicitly enabled.
-                 * Certain characters (as given by the CTRL_ALWAYS
-                 * bitmap) are always displayed as control characters,
-                 * as the console would be pretty useless without
-                 * them; to display an arbitrary font position use the
-                 * direct-to-font zone in UTF-8 mode.
-                 */
-                ok = tc && (c >= 32 ||
-                           !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 :
-                                 vc->vc_utf || ((CTRL_ACTION >> c) & 1)))
-                       && (c != 127 || vc->vc_disp_ctrl)
-                       && (c != 128+27);
-
-               if (vc->vc_state == ESnormal && ok) {
-                       if (vc->vc_utf && !vc->vc_disp_ctrl) {
-                               if (is_double_width(c))
-                                       width = 2;
-                       }
-                       /* Now try to find out how to display it */
-                       tc = conv_uni_to_pc(vc, tc);
-                       if (tc & ~charmask) {
-                               if (tc == -1 || tc == -2) {
-                                   continue; /* nothing to display */
-                               }
-                               /* Glyph not found */
-                               if ((!(vc->vc_utf && !vc->vc_disp_ctrl) || c < 128) && !(c & ~charmask)) {
-                                   /* In legacy mode use the glyph we get by a 1:1 mapping.
-                                      This would make absolutely no sense with Unicode in mind,
-                                      but do this for ASCII characters since a font may lack
-                                      Unicode mapping info and we don't want to end up with
-                                      having question marks only. */
-                                   tc = c;
-                               } else {
-                                   /* Display U+FFFD. If it's not found, display an inverse question mark. */
-                                   tc = conv_uni_to_pc(vc, 0xfffd);
-                                   if (tc < 0) {
-                                       inverse = 1;
-                                       tc = conv_uni_to_pc(vc, '?');
-                                       if (tc < 0) tc = '?';
-                                   }
-                               }
-                       }
-
-                       if (!inverse) {
-                               vc_attr = vc->vc_attr;
-                       } else {
-                               /* invert vc_attr */
-                               if (!vc->vc_can_do_color) {
-                                       vc_attr = (vc->vc_attr) ^ 0x08;
-                               } else if (vc->vc_hi_font_mask == 0x100) {
-                                       vc_attr = ((vc->vc_attr) & 0x11) | (((vc->vc_attr) & 0xe0) >> 4) | (((vc->vc_attr) & 0x0e) << 4);
-                               } else {
-                                       vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4);
-                               }
-                               FLUSH
-                       }
-
-                       while (1) {
-                               if (vc->vc_need_wrap || vc->vc_decim)
-                                       FLUSH
-                               if (vc->vc_need_wrap) {
-                                       cr(vc);
-                                       lf(vc);
-                               }
-                               if (vc->vc_decim)
-                                       insert_char(vc, 1);
-                               scr_writew(himask ?
-                                            ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
-                                            (vc_attr << 8) + tc,
-                                          (u16 *) vc->vc_pos);
-                               if (DO_UPDATE(vc) && draw_x < 0) {
-                                       draw_x = vc->vc_x;
-                                       draw_from = vc->vc_pos;
-                               }
-                               if (vc->vc_x == vc->vc_cols - 1) {
-                                       vc->vc_need_wrap = vc->vc_decawm;
-                                       draw_to = vc->vc_pos + 2;
-                               } else {
-                                       vc->vc_x++;
-                                       draw_to = (vc->vc_pos += 2);
-                               }
-
-                               if (!--width) break;
-
-                               tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */
-                               if (tc < 0) tc = ' ';
-                       }
-                       notify_write(vc, c);
-
-                       if (inverse) {
-                               FLUSH
-                       }
-
-                       if (rescan) {
-                               rescan = 0;
-                               inverse = 0;
-                               width = 1;
-                               c = orig;
-                               goto rescan_last_byte;
-                       }
-                       continue;
-               }
-               FLUSH
-               do_con_trol(tty, vc, orig);
-       }
-       FLUSH
-       console_conditional_schedule();
-       release_console_sem();
-       notify_update(vc);
-       return n;
-#undef FLUSH
-}
-
-/*
- * This is the console switching callback.
- *
- * Doing console switching in a process context allows
- * us to do the switches asynchronously (needed when we want
- * to switch due to a keyboard interrupt).  Synchronization
- * with other console code and prevention of re-entrancy is
- * ensured with console_sem.
- */
-static void console_callback(struct work_struct *ignored)
-{
-       acquire_console_sem();
-
-       if (want_console >= 0) {
-               if (want_console != fg_console &&
-                   vc_cons_allocated(want_console)) {
-                       hide_cursor(vc_cons[fg_console].d);
-                       change_console(vc_cons[want_console].d);
-                       /* we only changed when the console had already
-                          been allocated - a new console is not created
-                          in an interrupt routine */
-               }
-               want_console = -1;
-       }
-       if (do_poke_blanked_console) { /* do not unblank for a LED change */
-               do_poke_blanked_console = 0;
-               poke_blanked_console();
-       }
-       if (scrollback_delta) {
-               struct vc_data *vc = vc_cons[fg_console].d;
-               clear_selection();
-               if (vc->vc_mode == KD_TEXT)
-                       vc->vc_sw->con_scrolldelta(vc, scrollback_delta);
-               scrollback_delta = 0;
-       }
-       if (blank_timer_expired) {
-               do_blank_screen(0);
-               blank_timer_expired = 0;
-       }
-       notify_update(vc_cons[fg_console].d);
-
-       release_console_sem();
-}
-
-int set_console(int nr)
-{
-       struct vc_data *vc = vc_cons[fg_console].d;
-
-       if (!vc_cons_allocated(nr) || vt_dont_switch ||
-               (vc->vt_mode.mode == VT_AUTO && vc->vc_mode == KD_GRAPHICS)) {
-
-               /*
-                * Console switch will fail in console_callback() or
-                * change_console() so there is no point scheduling
-                * the callback
-                *
-                * Existing set_console() users don't check the return
-                * value so this shouldn't break anything
-                */
-               return -EINVAL;
-       }
-
-       want_console = nr;
-       schedule_console_callback();
-
-       return 0;
-}
-
-struct tty_driver *console_driver;
-
-#ifdef CONFIG_VT_CONSOLE
-
-/**
- * vt_kmsg_redirect() - Sets/gets the kernel message console
- * @new:       The new virtual terminal number or -1 if the console should stay
- *             unchanged
- *
- * By default, the kernel messages are always printed on the current virtual
- * console. However, the user may modify that default with the
- * TIOCL_SETKMSGREDIRECT ioctl call.
- *
- * This function sets the kernel message console to be @new. It returns the old
- * virtual console number. The virtual terminal number 0 (both as parameter and
- * return value) means no redirection (i.e. always printed on the currently
- * active console).
- *
- * The parameter -1 means that only the current console is returned, but the
- * value is not modified. You may use the macro vt_get_kmsg_redirect() in that
- * case to make the code more understandable.
- *
- * When the kernel is compiled without CONFIG_VT_CONSOLE, this function ignores
- * the parameter and always returns 0.
- */
-int vt_kmsg_redirect(int new)
-{
-       static int kmsg_con;
-
-       if (new != -1)
-               return xchg(&kmsg_con, new);
-       else
-               return kmsg_con;
-}
-
-/*
- *     Console on virtual terminal
- *
- * The console must be locked when we get here.
- */
-
-static void vt_console_print(struct console *co, const char *b, unsigned count)
-{
-       struct vc_data *vc = vc_cons[fg_console].d;
-       unsigned char c;
-       static DEFINE_SPINLOCK(printing_lock);
-       const ushort *start;
-       ushort cnt = 0;
-       ushort myx;
-       int kmsg_console;
-
-       /* console busy or not yet initialized */
-       if (!printable)
-               return;
-       if (!spin_trylock(&printing_lock))
-               return;
-
-       kmsg_console = vt_get_kmsg_redirect();
-       if (kmsg_console && vc_cons_allocated(kmsg_console - 1))
-               vc = vc_cons[kmsg_console - 1].d;
-
-       /* read `x' only after setting currcons properly (otherwise
-          the `x' macro will read the x of the foreground console). */
-       myx = vc->vc_x;
-
-       if (!vc_cons_allocated(fg_console)) {
-               /* impossible */
-               /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */
-               goto quit;
-       }
-
-       if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc))
-               goto quit;
-
-       /* undraw cursor first */
-       if (IS_FG(vc))
-               hide_cursor(vc);
-
-       start = (ushort *)vc->vc_pos;
-
-       /* Contrived structure to try to emulate original need_wrap behaviour
-        * Problems caused when we have need_wrap set on '\n' character */
-       while (count--) {
-               c = *b++;
-               if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
-                       if (cnt > 0) {
-                               if (CON_IS_VISIBLE(vc))
-                                       vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
-                               vc->vc_x += cnt;
-                               if (vc->vc_need_wrap)
-                                       vc->vc_x--;
-                               cnt = 0;
-                       }
-                       if (c == 8) {           /* backspace */
-                               bs(vc);
-                               start = (ushort *)vc->vc_pos;
-                               myx = vc->vc_x;
-                               continue;
-                       }
-                       if (c != 13)
-                               lf(vc);
-                       cr(vc);
-                       start = (ushort *)vc->vc_pos;
-                       myx = vc->vc_x;
-                       if (c == 10 || c == 13)
-                               continue;
-               }
-               scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos);
-               notify_write(vc, c);
-               cnt++;
-               if (myx == vc->vc_cols - 1) {
-                       vc->vc_need_wrap = 1;
-                       continue;
-               }
-               vc->vc_pos += 2;
-               myx++;
-       }
-       if (cnt > 0) {
-               if (CON_IS_VISIBLE(vc))
-                       vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
-               vc->vc_x += cnt;
-               if (vc->vc_x == vc->vc_cols) {
-                       vc->vc_x--;
-                       vc->vc_need_wrap = 1;
-               }
-       }
-       set_cursor(vc);
-       notify_update(vc);
-
-quit:
-       spin_unlock(&printing_lock);
-}
-
-static struct tty_driver *vt_console_device(struct console *c, int *index)
-{
-       *index = c->index ? c->index-1 : fg_console;
-       return console_driver;
-}
-
-static struct console vt_console_driver = {
-       .name           = "tty",
-       .write          = vt_console_print,
-       .device         = vt_console_device,
-       .unblank        = unblank_screen,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-};
-#endif
-
-/*
- *     Handling of Linux-specific VC ioctls
- */
-
-/*
- * Generally a bit racy with respect to console_sem().
- *
- * There are some functions which don't need it.
- *
- * There are some functions which can sleep for arbitrary periods
- * (paste_selection) but we don't need the lock there anyway.
- *
- * set_selection has locking, and definitely needs it
- */
-
-int tioclinux(struct tty_struct *tty, unsigned long arg)
-{
-       char type, data;
-       char __user *p = (char __user *)arg;
-       int lines;
-       int ret;
-
-       if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN))
-               return -EPERM;
-       if (get_user(type, p))
-               return -EFAULT;
-       ret = 0;
-
-       switch (type)
-       {
-               case TIOCL_SETSEL:
-                       acquire_console_sem();
-                       ret = set_selection((struct tiocl_selection __user *)(p+1), tty);
-                       release_console_sem();
-                       break;
-               case TIOCL_PASTESEL:
-                       ret = paste_selection(tty);
-                       break;
-               case TIOCL_UNBLANKSCREEN:
-                       acquire_console_sem();
-                       unblank_screen();
-                       release_console_sem();
-                       break;
-               case TIOCL_SELLOADLUT:
-                       ret = sel_loadlut(p);
-                       break;
-               case TIOCL_GETSHIFTSTATE:
-
-       /*
-        * Make it possible to react to Shift+Mousebutton.
-        * Note that 'shift_state' is an undocumented
-        * kernel-internal variable; programs not closely
-        * related to the kernel should not use this.
-        */
-                       data = shift_state;
-                       ret = __put_user(data, p);
-                       break;
-               case TIOCL_GETMOUSEREPORTING:
-                       data = mouse_reporting();
-                       ret = __put_user(data, p);
-                       break;
-               case TIOCL_SETVESABLANK:
-                       ret = set_vesa_blanking(p);
-                       break;
-               case TIOCL_GETKMSGREDIRECT:
-                       data = vt_get_kmsg_redirect();
-                       ret = __put_user(data, p);
-                       break;
-               case TIOCL_SETKMSGREDIRECT:
-                       if (!capable(CAP_SYS_ADMIN)) {
-                               ret = -EPERM;
-                       } else {
-                               if (get_user(data, p+1))
-                                       ret = -EFAULT;
-                               else
-                                       vt_kmsg_redirect(data);
-                       }
-                       break;
-               case TIOCL_GETFGCONSOLE:
-                       ret = fg_console;
-                       break;
-               case TIOCL_SCROLLCONSOLE:
-                       if (get_user(lines, (s32 __user *)(p+4))) {
-                               ret = -EFAULT;
-                       } else {
-                               scrollfront(vc_cons[fg_console].d, lines);
-                               ret = 0;
-                       }
-                       break;
-               case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */
-                       acquire_console_sem();
-                       ignore_poke = 1;
-                       do_blank_screen(0);
-                       release_console_sem();
-                       break;
-               case TIOCL_BLANKEDSCREEN:
-                       ret = console_blanked;
-                       break;
-               default:
-                       ret = -EINVAL;
-                       break;
-       }
-       return ret;
-}
-
-/*
- * /dev/ttyN handling
- */
-
-static int con_write(struct tty_struct *tty, const unsigned char *buf, int count)
-{
-       int     retval;
-
-       retval = do_con_write(tty, buf, count);
-       con_flush_chars(tty);
-
-       return retval;
-}
-
-static int con_put_char(struct tty_struct *tty, unsigned char ch)
-{
-       if (in_interrupt())
-               return 0;       /* n_r3964 calls put_char() from interrupt context */
-       return do_con_write(tty, &ch, 1);
-}
-
-static int con_write_room(struct tty_struct *tty)
-{
-       if (tty->stopped)
-               return 0;
-       return 32768;           /* No limit, really; we're not buffering */
-}
-
-static int con_chars_in_buffer(struct tty_struct *tty)
-{
-       return 0;               /* we're not buffering */
-}
-
-/*
- * con_throttle and con_unthrottle are only used for
- * paste_selection(), which has to stuff in a large number of
- * characters...
- */
-static void con_throttle(struct tty_struct *tty)
-{
-}
-
-static void con_unthrottle(struct tty_struct *tty)
-{
-       struct vc_data *vc = tty->driver_data;
-
-       wake_up_interruptible(&vc->paste_wait);
-}
-
-/*
- * Turn the Scroll-Lock LED on when the tty is stopped
- */
-static void con_stop(struct tty_struct *tty)
-{
-       int console_num;
-       if (!tty)
-               return;
-       console_num = tty->index;
-       if (!vc_cons_allocated(console_num))
-               return;
-       set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
-       set_leds();
-}
-
-/*
- * Turn the Scroll-Lock LED off when the console is started
- */
-static void con_start(struct tty_struct *tty)
-{
-       int console_num;
-       if (!tty)
-               return;
-       console_num = tty->index;
-       if (!vc_cons_allocated(console_num))
-               return;
-       clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
-       set_leds();
-}
-
-static void con_flush_chars(struct tty_struct *tty)
-{
-       struct vc_data *vc;
-
-       if (in_interrupt())     /* from flush_to_ldisc */
-               return;
-
-       /* if we race with con_close(), vt may be null */
-       acquire_console_sem();
-       vc = tty->driver_data;
-       if (vc)
-               set_cursor(vc);
-       release_console_sem();
-}
-
-/*
- * Allocate the console screen memory.
- */
-static int con_open(struct tty_struct *tty, struct file *filp)
-{
-       unsigned int currcons = tty->index;
-       int ret = 0;
-
-       acquire_console_sem();
-       if (tty->driver_data == NULL) {
-               ret = vc_allocate(currcons);
-               if (ret == 0) {
-                       struct vc_data *vc = vc_cons[currcons].d;
-
-                       /* Still being freed */
-                       if (vc->port.tty) {
-                               release_console_sem();
-                               return -ERESTARTSYS;
-                       }
-                       tty->driver_data = vc;
-                       vc->port.tty = tty;
-
-                       if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
-                               tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
-                               tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
-                       }
-                       if (vc->vc_utf)
-                               tty->termios->c_iflag |= IUTF8;
-                       else
-                               tty->termios->c_iflag &= ~IUTF8;
-                       release_console_sem();
-                       return ret;
-               }
-       }
-       release_console_sem();
-       return ret;
-}
-
-static void con_close(struct tty_struct *tty, struct file *filp)
-{
-       /* Nothing to do - we defer to shutdown */
-}
-
-static void con_shutdown(struct tty_struct *tty)
-{
-       struct vc_data *vc = tty->driver_data;
-       BUG_ON(vc == NULL);
-       acquire_console_sem();
-       vc->port.tty = NULL;
-       release_console_sem();
-       tty_shutdown(tty);
-}
-
-static int default_italic_color    = 2; // green (ASCII)
-static int default_underline_color = 3; // cyan (ASCII)
-module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR);
-module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR);
-
-static void vc_init(struct vc_data *vc, unsigned int rows,
-                   unsigned int cols, int do_clear)
-{
-       int j, k ;
-
-       vc->vc_cols = cols;
-       vc->vc_rows = rows;
-       vc->vc_size_row = cols << 1;
-       vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
-
-       set_origin(vc);
-       vc->vc_pos = vc->vc_origin;
-       reset_vc(vc);
-       for (j=k=0; j<16; j++) {
-               vc->vc_palette[k++] = default_red[j] ;
-               vc->vc_palette[k++] = default_grn[j] ;
-               vc->vc_palette[k++] = default_blu[j] ;
-       }
-       vc->vc_def_color       = 0x07;   /* white */
-       vc->vc_ulcolor         = default_underline_color;
-       vc->vc_itcolor         = default_italic_color;
-       vc->vc_halfcolor       = 0x08;   /* grey */
-       init_waitqueue_head(&vc->paste_wait);
-       reset_terminal(vc, do_clear);
-}
-
-/*
- * This routine initializes console interrupts, and does nothing
- * else. If you want the screen to clear, call tty_write with
- * the appropriate escape-sequence.
- */
-
-static int __init con_init(void)
-{
-       const char *display_desc = NULL;
-       struct vc_data *vc;
-       unsigned int currcons = 0, i;
-
-       acquire_console_sem();
-
-       if (conswitchp)
-               display_desc = conswitchp->con_startup();
-       if (!display_desc) {
-               fg_console = 0;
-               release_console_sem();
-               return 0;
-       }
-
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               struct con_driver *con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == NULL) {
-                       con_driver->con = conswitchp;
-                       con_driver->desc = display_desc;
-                       con_driver->flag = CON_DRIVER_FLAG_INIT;
-                       con_driver->first = 0;
-                       con_driver->last = MAX_NR_CONSOLES - 1;
-                       break;
-               }
-       }
-
-       for (i = 0; i < MAX_NR_CONSOLES; i++)
-               con_driver_map[i] = conswitchp;
-
-       if (blankinterval) {
-               blank_state = blank_normal_wait;
-               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
-       }
-
-       for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
-               vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
-               INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
-               tty_port_init(&vc->port);
-               visual_init(vc, currcons, 1);
-               vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
-               vc_init(vc, vc->vc_rows, vc->vc_cols,
-                       currcons || !vc->vc_sw->con_save_screen);
-       }
-       currcons = fg_console = 0;
-       master_display_fg = vc = vc_cons[currcons].d;
-       set_origin(vc);
-       save_screen(vc);
-       gotoxy(vc, vc->vc_x, vc->vc_y);
-       csi_J(vc, 0);
-       update_screen(vc);
-       printk("Console: %s %s %dx%d",
-               vc->vc_can_do_color ? "colour" : "mono",
-               display_desc, vc->vc_cols, vc->vc_rows);
-       printable = 1;
-       printk("\n");
-
-       release_console_sem();
-
-#ifdef CONFIG_VT_CONSOLE
-       register_console(&vt_console_driver);
-#endif
-       return 0;
-}
-console_initcall(con_init);
-
-static const struct tty_operations con_ops = {
-       .open = con_open,
-       .close = con_close,
-       .write = con_write,
-       .write_room = con_write_room,
-       .put_char = con_put_char,
-       .flush_chars = con_flush_chars,
-       .chars_in_buffer = con_chars_in_buffer,
-       .ioctl = vt_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl = vt_compat_ioctl,
-#endif
-       .stop = con_stop,
-       .start = con_start,
-       .throttle = con_throttle,
-       .unthrottle = con_unthrottle,
-       .resize = vt_resize,
-       .shutdown = con_shutdown
-};
-
-static struct cdev vc0_cdev;
-
-int __init vty_init(const struct file_operations *console_fops)
-{
-       cdev_init(&vc0_cdev, console_fops);
-       if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
-           register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
-               panic("Couldn't register /dev/tty0 driver\n");
-       device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
-
-       vcs_init();
-
-       console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
-       if (!console_driver)
-               panic("Couldn't allocate console driver\n");
-       console_driver->owner = THIS_MODULE;
-       console_driver->name = "tty";
-       console_driver->name_base = 1;
-       console_driver->major = TTY_MAJOR;
-       console_driver->minor_start = 1;
-       console_driver->type = TTY_DRIVER_TYPE_CONSOLE;
-       console_driver->init_termios = tty_std_termios;
-       if (default_utf8)
-               console_driver->init_termios.c_iflag |= IUTF8;
-       console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
-       tty_set_operations(console_driver, &con_ops);
-       if (tty_register_driver(console_driver))
-               panic("Couldn't register console driver\n");
-       kbd_init();
-       console_map_init();
-#ifdef CONFIG_MDA_CONSOLE
-       mda_console_init();
-#endif
-       return 0;
-}
-
-#ifndef VT_SINGLE_DRIVER
-
-static struct class *vtconsole_class;
-
-static int bind_con_driver(const struct consw *csw, int first, int last,
-                          int deflt)
-{
-       struct module *owner = csw->owner;
-       const char *desc = NULL;
-       struct con_driver *con_driver;
-       int i, j = -1, k = -1, retval = -ENODEV;
-
-       if (!try_module_get(owner))
-               return -ENODEV;
-
-       acquire_console_sem();
-
-       /* check if driver is registered */
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == csw) {
-                       desc = con_driver->desc;
-                       retval = 0;
-                       break;
-               }
-       }
-
-       if (retval)
-               goto err;
-
-       if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) {
-               csw->con_startup();
-               con_driver->flag |= CON_DRIVER_FLAG_INIT;
-       }
-
-       if (deflt) {
-               if (conswitchp)
-                       module_put(conswitchp->owner);
-
-               __module_get(owner);
-               conswitchp = csw;
-       }
-
-       first = max(first, con_driver->first);
-       last = min(last, con_driver->last);
-
-       for (i = first; i <= last; i++) {
-               int old_was_color;
-               struct vc_data *vc = vc_cons[i].d;
-
-               if (con_driver_map[i])
-                       module_put(con_driver_map[i]->owner);
-               __module_get(owner);
-               con_driver_map[i] = csw;
-
-               if (!vc || !vc->vc_sw)
-                       continue;
-
-               j = i;
-
-               if (CON_IS_VISIBLE(vc)) {
-                       k = i;
-                       save_screen(vc);
-               }
-
-               old_was_color = vc->vc_can_do_color;
-               vc->vc_sw->con_deinit(vc);
-               vc->vc_origin = (unsigned long)vc->vc_screenbuf;
-               visual_init(vc, i, 0);
-               set_origin(vc);
-               update_attr(vc);
-
-               /* If the console changed between mono <-> color, then
-                * the attributes in the screenbuf will be wrong.  The
-                * following resets all attributes to something sane.
-                */
-               if (old_was_color != vc->vc_can_do_color)
-                       clear_buffer_attributes(vc);
-       }
-
-       printk("Console: switching ");
-       if (!deflt)
-               printk("consoles %d-%d ", first+1, last+1);
-       if (j >= 0) {
-               struct vc_data *vc = vc_cons[j].d;
-
-               printk("to %s %s %dx%d\n",
-                      vc->vc_can_do_color ? "colour" : "mono",
-                      desc, vc->vc_cols, vc->vc_rows);
-
-               if (k >= 0) {
-                       vc = vc_cons[k].d;
-                       update_screen(vc);
-               }
-       } else
-               printk("to %s\n", desc);
-
-       retval = 0;
-err:
-       release_console_sem();
-       module_put(owner);
-       return retval;
-};
-
-#ifdef CONFIG_VT_HW_CONSOLE_BINDING
-static int con_is_graphics(const struct consw *csw, int first, int last)
-{
-       int i, retval = 0;
-
-       for (i = first; i <= last; i++) {
-               struct vc_data *vc = vc_cons[i].d;
-
-               if (vc && vc->vc_mode == KD_GRAPHICS) {
-                       retval = 1;
-                       break;
-               }
-       }
-
-       return retval;
-}
-
-/**
- * unbind_con_driver - unbind a console driver
- * @csw: pointer to console driver to unregister
- * @first: first in range of consoles that @csw should be unbound from
- * @last: last in range of consoles that @csw should be unbound from
- * @deflt: should next bound console driver be default after @csw is unbound?
- *
- * To unbind a driver from all possible consoles, pass 0 as @first and
- * %MAX_NR_CONSOLES as @last.
- *
- * @deflt controls whether the console that ends up replacing @csw should be
- * the default console.
- *
- * RETURNS:
- * -ENODEV if @csw isn't a registered console driver or can't be unregistered
- * or 0 on success.
- */
-int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
-{
-       struct module *owner = csw->owner;
-       const struct consw *defcsw = NULL;
-       struct con_driver *con_driver = NULL, *con_back = NULL;
-       int i, retval = -ENODEV;
-
-       if (!try_module_get(owner))
-               return -ENODEV;
-
-       acquire_console_sem();
-
-       /* check if driver is registered and if it is unbindable */
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == csw &&
-                   con_driver->flag & CON_DRIVER_FLAG_MODULE) {
-                       retval = 0;
-                       break;
-               }
-       }
-
-       if (retval) {
-               release_console_sem();
-               goto err;
-       }
-
-       retval = -ENODEV;
-
-       /* check if backup driver exists */
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_back = &registered_con_driver[i];
-
-               if (con_back->con &&
-                   !(con_back->flag & CON_DRIVER_FLAG_MODULE)) {
-                       defcsw = con_back->con;
-                       retval = 0;
-                       break;
-               }
-       }
-
-       if (retval) {
-               release_console_sem();
-               goto err;
-       }
-
-       if (!con_is_bound(csw)) {
-               release_console_sem();
-               goto err;
-       }
-
-       first = max(first, con_driver->first);
-       last = min(last, con_driver->last);
-
-       for (i = first; i <= last; i++) {
-               if (con_driver_map[i] == csw) {
-                       module_put(csw->owner);
-                       con_driver_map[i] = NULL;
-               }
-       }
-
-       if (!con_is_bound(defcsw)) {
-               const struct consw *defconsw = conswitchp;
-
-               defcsw->con_startup();
-               con_back->flag |= CON_DRIVER_FLAG_INIT;
-               /*
-                * vgacon may change the default driver to point
-                * to dummycon, we restore it here...
-                */
-               conswitchp = defconsw;
-       }
-
-       if (!con_is_bound(csw))
-               con_driver->flag &= ~CON_DRIVER_FLAG_INIT;
-
-       release_console_sem();
-       /* ignore return value, binding should not fail */
-       bind_con_driver(defcsw, first, last, deflt);
-err:
-       module_put(owner);
-       return retval;
-
-}
-EXPORT_SYMBOL(unbind_con_driver);
-
-static int vt_bind(struct con_driver *con)
-{
-       const struct consw *defcsw = NULL, *csw = NULL;
-       int i, more = 1, first = -1, last = -1, deflt = 0;
-
-       if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
-           con_is_graphics(con->con, con->first, con->last))
-               goto err;
-
-       csw = con->con;
-
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               struct con_driver *con = &registered_con_driver[i];
-
-               if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) {
-                       defcsw = con->con;
-                       break;
-               }
-       }
-
-       if (!defcsw)
-               goto err;
-
-       while (more) {
-               more = 0;
-
-               for (i = con->first; i <= con->last; i++) {
-                       if (con_driver_map[i] == defcsw) {
-                               if (first == -1)
-                                       first = i;
-                               last = i;
-                               more = 1;
-                       } else if (first != -1)
-                               break;
-               }
-
-               if (first == 0 && last == MAX_NR_CONSOLES -1)
-                       deflt = 1;
-
-               if (first != -1)
-                       bind_con_driver(csw, first, last, deflt);
-
-               first = -1;
-               last = -1;
-               deflt = 0;
-       }
-
-err:
-       return 0;
-}
-
-static int vt_unbind(struct con_driver *con)
-{
-       const struct consw *csw = NULL;
-       int i, more = 1, first = -1, last = -1, deflt = 0;
-
-       if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
-           con_is_graphics(con->con, con->first, con->last))
-               goto err;
-
-       csw = con->con;
-
-       while (more) {
-               more = 0;
-
-               for (i = con->first; i <= con->last; i++) {
-                       if (con_driver_map[i] == csw) {
-                               if (first == -1)
-                                       first = i;
-                               last = i;
-                               more = 1;
-                       } else if (first != -1)
-                               break;
-               }
-
-               if (first == 0 && last == MAX_NR_CONSOLES -1)
-                       deflt = 1;
-
-               if (first != -1)
-                       unbind_con_driver(csw, first, last, deflt);
-
-               first = -1;
-               last = -1;
-               deflt = 0;
-       }
-
-err:
-       return 0;
-}
-#else
-static inline int vt_bind(struct con_driver *con)
-{
-       return 0;
-}
-static inline int vt_unbind(struct con_driver *con)
-{
-       return 0;
-}
-#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
-
-static ssize_t store_bind(struct device *dev, struct device_attribute *attr,
-                         const char *buf, size_t count)
-{
-       struct con_driver *con = dev_get_drvdata(dev);
-       int bind = simple_strtoul(buf, NULL, 0);
-
-       if (bind)
-               vt_bind(con);
-       else
-               vt_unbind(con);
-
-       return count;
-}
-
-static ssize_t show_bind(struct device *dev, struct device_attribute *attr,
-                        char *buf)
-{
-       struct con_driver *con = dev_get_drvdata(dev);
-       int bind = con_is_bound(con->con);
-
-       return snprintf(buf, PAGE_SIZE, "%i\n", bind);
-}
-
-static ssize_t show_name(struct device *dev, struct device_attribute *attr,
-                        char *buf)
-{
-       struct con_driver *con = dev_get_drvdata(dev);
-
-       return snprintf(buf, PAGE_SIZE, "%s %s\n",
-                       (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)",
-                        con->desc);
-
-}
-
-static struct device_attribute device_attrs[] = {
-       __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind),
-       __ATTR(name, S_IRUGO, show_name, NULL),
-};
-
-static int vtconsole_init_device(struct con_driver *con)
-{
-       int i;
-       int error = 0;
-
-       con->flag |= CON_DRIVER_FLAG_ATTR;
-       dev_set_drvdata(con->dev, con);
-       for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
-               error = device_create_file(con->dev, &device_attrs[i]);
-               if (error)
-                       break;
-       }
-
-       if (error) {
-               while (--i >= 0)
-                       device_remove_file(con->dev, &device_attrs[i]);
-               con->flag &= ~CON_DRIVER_FLAG_ATTR;
-       }
-
-       return error;
-}
-
-static void vtconsole_deinit_device(struct con_driver *con)
-{
-       int i;
-
-       if (con->flag & CON_DRIVER_FLAG_ATTR) {
-               for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
-                       device_remove_file(con->dev, &device_attrs[i]);
-               con->flag &= ~CON_DRIVER_FLAG_ATTR;
-       }
-}
-
-/**
- * con_is_bound - checks if driver is bound to the console
- * @csw: console driver
- *
- * RETURNS: zero if unbound, nonzero if bound
- *
- * Drivers can call this and if zero, they should release
- * all resources allocated on con_startup()
- */
-int con_is_bound(const struct consw *csw)
-{
-       int i, bound = 0;
-
-       for (i = 0; i < MAX_NR_CONSOLES; i++) {
-               if (con_driver_map[i] == csw) {
-                       bound = 1;
-                       break;
-               }
-       }
-
-       return bound;
-}
-EXPORT_SYMBOL(con_is_bound);
-
-/**
- * con_debug_enter - prepare the console for the kernel debugger
- * @sw: console driver
- *
- * Called when the console is taken over by the kernel debugger, this
- * function needs to save the current console state, then put the console
- * into a state suitable for the kernel debugger.
- *
- * RETURNS:
- * Zero on success, nonzero if a failure occurred when trying to prepare
- * the console for the debugger.
- */
-int con_debug_enter(struct vc_data *vc)
-{
-       int ret = 0;
-
-       saved_fg_console = fg_console;
-       saved_last_console = last_console;
-       saved_want_console = want_console;
-       saved_vc_mode = vc->vc_mode;
-       saved_console_blanked = console_blanked;
-       vc->vc_mode = KD_TEXT;
-       console_blanked = 0;
-       if (vc->vc_sw->con_debug_enter)
-               ret = vc->vc_sw->con_debug_enter(vc);
-#ifdef CONFIG_KGDB_KDB
-       /* Set the initial LINES variable if it is not already set */
-       if (vc->vc_rows < 999) {
-               int linecount;
-               char lns[4];
-               const char *setargs[3] = {
-                       "set",
-                       "LINES",
-                       lns,
-               };
-               if (kdbgetintenv(setargs[0], &linecount)) {
-                       snprintf(lns, 4, "%i", vc->vc_rows);
-                       kdb_set(2, setargs);
-               }
-       }
-#endif /* CONFIG_KGDB_KDB */
-       return ret;
-}
-EXPORT_SYMBOL_GPL(con_debug_enter);
-
-/**
- * con_debug_leave - restore console state
- * @sw: console driver
- *
- * Restore the console state to what it was before the kernel debugger
- * was invoked.
- *
- * RETURNS:
- * Zero on success, nonzero if a failure occurred when trying to restore
- * the console.
- */
-int con_debug_leave(void)
-{
-       struct vc_data *vc;
-       int ret = 0;
-
-       fg_console = saved_fg_console;
-       last_console = saved_last_console;
-       want_console = saved_want_console;
-       console_blanked = saved_console_blanked;
-       vc_cons[fg_console].d->vc_mode = saved_vc_mode;
-
-       vc = vc_cons[fg_console].d;
-       if (vc->vc_sw->con_debug_leave)
-               ret = vc->vc_sw->con_debug_leave(vc);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(con_debug_leave);
-
-/**
- * register_con_driver - register console driver to console layer
- * @csw: console driver
- * @first: the first console to take over, minimum value is 0
- * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1
- *
- * DESCRIPTION: This function registers a console driver which can later
- * bind to a range of consoles specified by @first and @last. It will
- * also initialize the console driver by calling con_startup().
- */
-int register_con_driver(const struct consw *csw, int first, int last)
-{
-       struct module *owner = csw->owner;
-       struct con_driver *con_driver;
-       const char *desc;
-       int i, retval = 0;
-
-       if (!try_module_get(owner))
-               return -ENODEV;
-
-       acquire_console_sem();
-
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_driver = &registered_con_driver[i];
-
-               /* already registered */
-               if (con_driver->con == csw)
-                       retval = -EINVAL;
-       }
-
-       if (retval)
-               goto err;
-
-       desc = csw->con_startup();
-
-       if (!desc)
-               goto err;
-
-       retval = -EINVAL;
-
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == NULL) {
-                       con_driver->con = csw;
-                       con_driver->desc = desc;
-                       con_driver->node = i;
-                       con_driver->flag = CON_DRIVER_FLAG_MODULE |
-                                          CON_DRIVER_FLAG_INIT;
-                       con_driver->first = first;
-                       con_driver->last = last;
-                       retval = 0;
-                       break;
-               }
-       }
-
-       if (retval)
-               goto err;
-
-       con_driver->dev = device_create(vtconsole_class, NULL,
-                                               MKDEV(0, con_driver->node),
-                                               NULL, "vtcon%i",
-                                               con_driver->node);
-
-       if (IS_ERR(con_driver->dev)) {
-               printk(KERN_WARNING "Unable to create device for %s; "
-                      "errno = %ld\n", con_driver->desc,
-                      PTR_ERR(con_driver->dev));
-               con_driver->dev = NULL;
-       } else {
-               vtconsole_init_device(con_driver);
-       }
-
-err:
-       release_console_sem();
-       module_put(owner);
-       return retval;
-}
-EXPORT_SYMBOL(register_con_driver);
-
-/**
- * unregister_con_driver - unregister console driver from console layer
- * @csw: console driver
- *
- * DESCRIPTION: All drivers that registers to the console layer must
- * call this function upon exit, or if the console driver is in a state
- * where it won't be able to handle console services, such as the
- * framebuffer console without loaded framebuffer drivers.
- *
- * The driver must unbind first prior to unregistration.
- */
-int unregister_con_driver(const struct consw *csw)
-{
-       int i, retval = -ENODEV;
-
-       acquire_console_sem();
-
-       /* cannot unregister a bound driver */
-       if (con_is_bound(csw))
-               goto err;
-
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               struct con_driver *con_driver = &registered_con_driver[i];
-
-               if (con_driver->con == csw &&
-                   con_driver->flag & CON_DRIVER_FLAG_MODULE) {
-                       vtconsole_deinit_device(con_driver);
-                       device_destroy(vtconsole_class,
-                                      MKDEV(0, con_driver->node));
-                       con_driver->con = NULL;
-                       con_driver->desc = NULL;
-                       con_driver->dev = NULL;
-                       con_driver->node = 0;
-                       con_driver->flag = 0;
-                       con_driver->first = 0;
-                       con_driver->last = 0;
-                       retval = 0;
-                       break;
-               }
-       }
-err:
-       release_console_sem();
-       return retval;
-}
-EXPORT_SYMBOL(unregister_con_driver);
-
-/*
- *     If we support more console drivers, this function is used
- *     when a driver wants to take over some existing consoles
- *     and become default driver for newly opened ones.
- *
- *      take_over_console is basically a register followed by unbind
- */
-int take_over_console(const struct consw *csw, int first, int last, int deflt)
-{
-       int err;
-
-       err = register_con_driver(csw, first, last);
-
-       if (!err)
-               bind_con_driver(csw, first, last, deflt);
-
-       return err;
-}
-
-/*
- * give_up_console is a wrapper to unregister_con_driver. It will only
- * work if driver is fully unbound.
- */
-void give_up_console(const struct consw *csw)
-{
-       unregister_con_driver(csw);
-}
-
-static int __init vtconsole_class_init(void)
-{
-       int i;
-
-       vtconsole_class = class_create(THIS_MODULE, "vtconsole");
-       if (IS_ERR(vtconsole_class)) {
-               printk(KERN_WARNING "Unable to create vt console class; "
-                      "errno = %ld\n", PTR_ERR(vtconsole_class));
-               vtconsole_class = NULL;
-       }
-
-       /* Add system drivers to sysfs */
-       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
-               struct con_driver *con = &registered_con_driver[i];
-
-               if (con->con && !con->dev) {
-                       con->dev = device_create(vtconsole_class, NULL,
-                                                        MKDEV(0, con->node),
-                                                        NULL, "vtcon%i",
-                                                        con->node);
-
-                       if (IS_ERR(con->dev)) {
-                               printk(KERN_WARNING "Unable to create "
-                                      "device for %s; errno = %ld\n",
-                                      con->desc, PTR_ERR(con->dev));
-                               con->dev = NULL;
-                       } else {
-                               vtconsole_init_device(con);
-                       }
-               }
-       }
-
-       return 0;
-}
-postcore_initcall(vtconsole_class_init);
-
-#endif
-
-/*
- *     Screen blanking
- */
-
-static int set_vesa_blanking(char __user *p)
-{
-       unsigned int mode;
-
-       if (get_user(mode, p + 1))
-               return -EFAULT;
-
-       vesa_blank_mode = (mode < 4) ? mode : 0;
-       return 0;
-}
-
-void do_blank_screen(int entering_gfx)
-{
-       struct vc_data *vc = vc_cons[fg_console].d;
-       int i;
-
-       WARN_CONSOLE_UNLOCKED();
-
-       if (console_blanked) {
-               if (blank_state == blank_vesa_wait) {
-                       blank_state = blank_off;
-                       vc->vc_sw->con_blank(vc, vesa_blank_mode + 1, 0);
-               }
-               return;
-       }
-
-       /* entering graphics mode? */
-       if (entering_gfx) {
-               hide_cursor(vc);
-               save_screen(vc);
-               vc->vc_sw->con_blank(vc, -1, 1);
-               console_blanked = fg_console + 1;
-               blank_state = blank_off;
-               set_origin(vc);
-               return;
-       }
-
-       if (blank_state != blank_normal_wait)
-               return;
-       blank_state = blank_off;
-
-       /* don't blank graphics */
-       if (vc->vc_mode != KD_TEXT) {
-               console_blanked = fg_console + 1;
-               return;
-       }
-
-       hide_cursor(vc);
-       del_timer_sync(&console_timer);
-       blank_timer_expired = 0;
-
-       save_screen(vc);
-       /* In case we need to reset origin, blanking hook returns 1 */
-       i = vc->vc_sw->con_blank(vc, vesa_off_interval ? 1 : (vesa_blank_mode + 1), 0);
-       console_blanked = fg_console + 1;
-       if (i)
-               set_origin(vc);
-
-       if (console_blank_hook && console_blank_hook(1))
-               return;
-
-       if (vesa_off_interval && vesa_blank_mode) {
-               blank_state = blank_vesa_wait;
-               mod_timer(&console_timer, jiffies + vesa_off_interval);
-       }
-       vt_event_post(VT_EVENT_BLANK, vc->vc_num, vc->vc_num);
-}
-EXPORT_SYMBOL(do_blank_screen);
-
-/*
- * Called by timer as well as from vt_console_driver
- */
-void do_unblank_screen(int leaving_gfx)
-{
-       struct vc_data *vc;
-
-       /* This should now always be called from a "sane" (read: can schedule)
-        * context for the sake of the low level drivers, except in the special
-        * case of oops_in_progress
-        */
-       if (!oops_in_progress)
-               might_sleep();
-
-       WARN_CONSOLE_UNLOCKED();
-
-       ignore_poke = 0;
-       if (!console_blanked)
-               return;
-       if (!vc_cons_allocated(fg_console)) {
-               /* impossible */
-               printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
-               return;
-       }
-       vc = vc_cons[fg_console].d;
-       /* Try to unblank in oops case too */
-       if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc))
-               return; /* but leave console_blanked != 0 */
-
-       if (blankinterval) {
-               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
-               blank_state = blank_normal_wait;
-       }
-
-       console_blanked = 0;
-       if (vc->vc_sw->con_blank(vc, 0, leaving_gfx) || vt_force_oops_output(vc))
-               /* Low-level driver cannot restore -> do it ourselves */
-               update_screen(vc);
-       if (console_blank_hook)
-               console_blank_hook(0);
-       set_palette(vc);
-       set_cursor(vc);
-       vt_event_post(VT_EVENT_UNBLANK, vc->vc_num, vc->vc_num);
-}
-EXPORT_SYMBOL(do_unblank_screen);
-
-/*
- * This is called by the outside world to cause a forced unblank, mostly for
- * oopses. Currently, I just call do_unblank_screen(0), but we could eventually
- * call it with 1 as an argument and so force a mode restore... that may kill
- * X or at least garbage the screen but would also make the Oops visible...
- */
-void unblank_screen(void)
-{
-       do_unblank_screen(0);
-}
-
-/*
- * We defer the timer blanking to work queue so it can take the console mutex
- * (console operations can still happen at irq time, but only from printk which
- * has the console mutex. Not perfect yet, but better than no locking
- */
-static void blank_screen_t(unsigned long dummy)
-{
-       if (unlikely(!keventd_up())) {
-               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
-               return;
-       }
-       blank_timer_expired = 1;
-       schedule_work(&console_work);
-}
-
-void poke_blanked_console(void)
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       /* Add this so we quickly catch whoever might call us in a non
-        * safe context. Nowadays, unblank_screen() isn't to be called in
-        * atomic contexts and is allowed to schedule (with the special case
-        * of oops_in_progress, but that isn't of any concern for this
-        * function. --BenH.
-        */
-       might_sleep();
-
-       /* This isn't perfectly race free, but a race here would be mostly harmless,
-        * at worse, we'll do a spurrious blank and it's unlikely
-        */
-       del_timer(&console_timer);
-       blank_timer_expired = 0;
-
-       if (ignore_poke || !vc_cons[fg_console].d || vc_cons[fg_console].d->vc_mode == KD_GRAPHICS)
-               return;
-       if (console_blanked)
-               unblank_screen();
-       else if (blankinterval) {
-               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
-               blank_state = blank_normal_wait;
-       }
-}
-
-/*
- *     Palettes
- */
-
-static void set_palette(struct vc_data *vc)
-{
-       WARN_CONSOLE_UNLOCKED();
-
-       if (vc->vc_mode != KD_GRAPHICS)
-               vc->vc_sw->con_set_palette(vc, color_table);
-}
-
-static int set_get_cmap(unsigned char __user *arg, int set)
-{
-    int i, j, k;
-
-    WARN_CONSOLE_UNLOCKED();
-
-    for (i = 0; i < 16; i++)
-       if (set) {
-           get_user(default_red[i], arg++);
-           get_user(default_grn[i], arg++);
-           get_user(default_blu[i], arg++);
-       } else {
-           put_user(default_red[i], arg++);
-           put_user(default_grn[i], arg++);
-           put_user(default_blu[i], arg++);
-       }
-    if (set) {
-       for (i = 0; i < MAX_NR_CONSOLES; i++)
-           if (vc_cons_allocated(i)) {
-               for (j = k = 0; j < 16; j++) {
-                   vc_cons[i].d->vc_palette[k++] = default_red[j];
-                   vc_cons[i].d->vc_palette[k++] = default_grn[j];
-                   vc_cons[i].d->vc_palette[k++] = default_blu[j];
-               }
-               set_palette(vc_cons[i].d);
-           }
-    }
-    return 0;
-}
-
-/*
- * Load palette into the DAC registers. arg points to a colour
- * map, 3 bytes per colour, 16 colours, range from 0 to 255.
- */
-
-int con_set_cmap(unsigned char __user *arg)
-{
-       int rc;
-
-       acquire_console_sem();
-       rc = set_get_cmap (arg,1);
-       release_console_sem();
-
-       return rc;
-}
-
-int con_get_cmap(unsigned char __user *arg)
-{
-       int rc;
-
-       acquire_console_sem();
-       rc = set_get_cmap (arg,0);
-       release_console_sem();
-
-       return rc;
-}
-
-void reset_palette(struct vc_data *vc)
-{
-       int j, k;
-       for (j=k=0; j<16; j++) {
-               vc->vc_palette[k++] = default_red[j];
-               vc->vc_palette[k++] = default_grn[j];
-               vc->vc_palette[k++] = default_blu[j];
-       }
-       set_palette(vc);
-}
-
-/*
- *  Font switching
- *
- *  Currently we only support fonts up to 32 pixels wide, at a maximum height
- *  of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, 
- *  depending on width) reserved for each character which is kinda wasty, but 
- *  this is done in order to maintain compatibility with the EGA/VGA fonts. It 
- *  is upto the actual low-level console-driver convert data into its favorite
- *  format (maybe we should add a `fontoffset' field to the `display'
- *  structure so we won't have to convert the fontdata all the time.
- *  /Jes
- */
-
-#define max_font_size 65536
-
-static int con_font_get(struct vc_data *vc, struct console_font_op *op)
-{
-       struct console_font font;
-       int rc = -EINVAL;
-       int c;
-
-       if (vc->vc_mode != KD_TEXT)
-               return -EINVAL;
-
-       if (op->data) {
-               font.data = kmalloc(max_font_size, GFP_KERNEL);
-               if (!font.data)
-                       return -ENOMEM;
-       } else
-               font.data = NULL;
-
-       acquire_console_sem();
-       if (vc->vc_sw->con_font_get)
-               rc = vc->vc_sw->con_font_get(vc, &font);
-       else
-               rc = -ENOSYS;
-       release_console_sem();
-
-       if (rc)
-               goto out;
-
-       c = (font.width+7)/8 * 32 * font.charcount;
-
-       if (op->data && font.charcount > op->charcount)
-               rc = -ENOSPC;
-       if (!(op->flags & KD_FONT_FLAG_OLD)) {
-               if (font.width > op->width || font.height > op->height) 
-                       rc = -ENOSPC;
-       } else {
-               if (font.width != 8)
-                       rc = -EIO;
-               else if ((op->height && font.height > op->height) ||
-                        font.height > 32)
-                       rc = -ENOSPC;
-       }
-       if (rc)
-               goto out;
-
-       op->height = font.height;
-       op->width = font.width;
-       op->charcount = font.charcount;
-
-       if (op->data && copy_to_user(op->data, font.data, c))
-               rc = -EFAULT;
-
-out:
-       kfree(font.data);
-       return rc;
-}
-
-static int con_font_set(struct vc_data *vc, struct console_font_op *op)
-{
-       struct console_font font;
-       int rc = -EINVAL;
-       int size;
-
-       if (vc->vc_mode != KD_TEXT)
-               return -EINVAL;
-       if (!op->data)
-               return -EINVAL;
-       if (op->charcount > 512)
-               return -EINVAL;
-       if (!op->height) {              /* Need to guess font height [compat] */
-               int h, i;
-               u8 __user *charmap = op->data;
-               u8 tmp;
-               
-               /* If from KDFONTOP ioctl, don't allow things which can be done in userland,
-                  so that we can get rid of this soon */
-               if (!(op->flags & KD_FONT_FLAG_OLD))
-                       return -EINVAL;
-               for (h = 32; h > 0; h--)
-                       for (i = 0; i < op->charcount; i++) {
-                               if (get_user(tmp, &charmap[32*i+h-1]))
-                                       return -EFAULT;
-                               if (tmp)
-                                       goto nonzero;
-                       }
-               return -EINVAL;
-       nonzero:
-               op->height = h;
-       }
-       if (op->width <= 0 || op->width > 32 || op->height > 32)
-               return -EINVAL;
-       size = (op->width+7)/8 * 32 * op->charcount;
-       if (size > max_font_size)
-               return -ENOSPC;
-       font.charcount = op->charcount;
-       font.height = op->height;
-       font.width = op->width;
-       font.data = memdup_user(op->data, size);
-       if (IS_ERR(font.data))
-               return PTR_ERR(font.data);
-       acquire_console_sem();
-       if (vc->vc_sw->con_font_set)
-               rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
-       else
-               rc = -ENOSYS;
-       release_console_sem();
-       kfree(font.data);
-       return rc;
-}
-
-static int con_font_default(struct vc_data *vc, struct console_font_op *op)
-{
-       struct console_font font = {.width = op->width, .height = op->height};
-       char name[MAX_FONT_NAME];
-       char *s = name;
-       int rc;
-
-       if (vc->vc_mode != KD_TEXT)
-               return -EINVAL;
-
-       if (!op->data)
-               s = NULL;
-       else if (strncpy_from_user(name, op->data, MAX_FONT_NAME - 1) < 0)
-               return -EFAULT;
-       else
-               name[MAX_FONT_NAME - 1] = 0;
-
-       acquire_console_sem();
-       if (vc->vc_sw->con_font_default)
-               rc = vc->vc_sw->con_font_default(vc, &font, s);
-       else
-               rc = -ENOSYS;
-       release_console_sem();
-       if (!rc) {
-               op->width = font.width;
-               op->height = font.height;
-       }
-       return rc;
-}
-
-static int con_font_copy(struct vc_data *vc, struct console_font_op *op)
-{
-       int con = op->height;
-       int rc;
-
-       if (vc->vc_mode != KD_TEXT)
-               return -EINVAL;
-
-       acquire_console_sem();
-       if (!vc->vc_sw->con_font_copy)
-               rc = -ENOSYS;
-       else if (con < 0 || !vc_cons_allocated(con))
-               rc = -ENOTTY;
-       else if (con == vc->vc_num)     /* nothing to do */
-               rc = 0;
-       else
-               rc = vc->vc_sw->con_font_copy(vc, con);
-       release_console_sem();
-       return rc;
-}
-
-int con_font_op(struct vc_data *vc, struct console_font_op *op)
-{
-       switch (op->op) {
-       case KD_FONT_OP_SET:
-               return con_font_set(vc, op);
-       case KD_FONT_OP_GET:
-               return con_font_get(vc, op);
-       case KD_FONT_OP_SET_DEFAULT:
-               return con_font_default(vc, op);
-       case KD_FONT_OP_COPY:
-               return con_font_copy(vc, op);
-       }
-       return -ENOSYS;
-}
-
-/*
- *     Interface exported to selection and vcs.
- */
-
-/* used by selection */
-u16 screen_glyph(struct vc_data *vc, int offset)
-{
-       u16 w = scr_readw(screenpos(vc, offset, 1));
-       u16 c = w & 0xff;
-
-       if (w & vc->vc_hi_font_mask)
-               c |= 0x100;
-       return c;
-}
-EXPORT_SYMBOL_GPL(screen_glyph);
-
-/* used by vcs - note the word offset */
-unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
-{
-       return screenpos(vc, 2 * w_offset, viewed);
-}
-
-void getconsxy(struct vc_data *vc, unsigned char *p)
-{
-       p[0] = vc->vc_x;
-       p[1] = vc->vc_y;
-}
-
-void putconsxy(struct vc_data *vc, unsigned char *p)
-{
-       hide_cursor(vc);
-       gotoxy(vc, p[0], p[1]);
-       set_cursor(vc);
-}
-
-u16 vcs_scr_readw(struct vc_data *vc, const u16 *org)
-{
-       if ((unsigned long)org == vc->vc_pos && softcursor_original != -1)
-               return softcursor_original;
-       return scr_readw(org);
-}
-
-void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org)
-{
-       scr_writew(val, org);
-       if ((unsigned long)org == vc->vc_pos) {
-               softcursor_original = -1;
-               add_softcursor(vc);
-       }
-}
-
-void vcs_scr_updated(struct vc_data *vc)
-{
-       notify_update(vc);
-}
-
-/*
- *     Visible symbols for modules
- */
-
-EXPORT_SYMBOL(color_table);
-EXPORT_SYMBOL(default_red);
-EXPORT_SYMBOL(default_grn);
-EXPORT_SYMBOL(default_blu);
-EXPORT_SYMBOL(update_region);
-EXPORT_SYMBOL(redraw_screen);
-EXPORT_SYMBOL(vc_resize);
-EXPORT_SYMBOL(fg_console);
-EXPORT_SYMBOL(console_blank_hook);
-EXPORT_SYMBOL(console_blanked);
-EXPORT_SYMBOL(vc_cons);
-EXPORT_SYMBOL(global_cursor_default);
-#ifndef VT_SINGLE_DRIVER
-EXPORT_SYMBOL(take_over_console);
-EXPORT_SYMBOL(give_up_console);
-#endif
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
deleted file mode 100644 (file)
index 6b68a0f..0000000
+++ /dev/null
@@ -1,1788 +0,0 @@
-/*
- *  linux/drivers/char/vt_ioctl.c
- *
- *  Copyright (C) 1992 obz under the linux copyright
- *
- *  Dynamic diacritical handling - aeb@cwi.nl - Dec 1993
- *  Dynamic keymap and string allocation - aeb@cwi.nl - May 1994
- *  Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995
- *  Some code moved for less code duplication - Andi Kleen - Mar 1997
- *  Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001
- */
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/tty.h>
-#include <linux/timer.h>
-#include <linux/kernel.h>
-#include <linux/compat.h>
-#include <linux/module.h>
-#include <linux/kd.h>
-#include <linux/vt.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/major.h>
-#include <linux/fs.h>
-#include <linux/console.h>
-#include <linux/consolemap.h>
-#include <linux/signal.h>
-#include <linux/smp_lock.h>
-#include <linux/timex.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/kbd_diacr.h>
-#include <linux/selection.h>
-
-char vt_dont_switch;
-extern struct tty_driver *console_driver;
-
-#define VT_IS_IN_USE(i)        (console_driver->ttys[i] && console_driver->ttys[i]->count)
-#define VT_BUSY(i)     (VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons)
-
-/*
- * Console (vt and kd) routines, as defined by USL SVR4 manual, and by
- * experimentation and study of X386 SYSV handling.
- *
- * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and
- * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console,
- * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will
- * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to
- * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using
- * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing
- * to the current console is done by the main ioctl code.
- */
-
-#ifdef CONFIG_X86
-#include <linux/syscalls.h>
-#endif
-
-static void complete_change_console(struct vc_data *vc);
-
-/*
- *     User space VT_EVENT handlers
- */
-
-struct vt_event_wait {
-       struct list_head list;
-       struct vt_event event;
-       int done;
-};
-
-static LIST_HEAD(vt_events);
-static DEFINE_SPINLOCK(vt_event_lock);
-static DECLARE_WAIT_QUEUE_HEAD(vt_event_waitqueue);
-
-/**
- *     vt_event_post
- *     @event: the event that occurred
- *     @old: old console
- *     @new: new console
- *
- *     Post an VT event to interested VT handlers
- */
-
-void vt_event_post(unsigned int event, unsigned int old, unsigned int new)
-{
-       struct list_head *pos, *head;
-       unsigned long flags;
-       int wake = 0;
-
-       spin_lock_irqsave(&vt_event_lock, flags);
-       head = &vt_events;
-
-       list_for_each(pos, head) {
-               struct vt_event_wait *ve = list_entry(pos,
-                                               struct vt_event_wait, list);
-               if (!(ve->event.event & event))
-                       continue;
-               ve->event.event = event;
-               /* kernel view is consoles 0..n-1, user space view is
-                  console 1..n with 0 meaning current, so we must bias */
-               ve->event.oldev = old + 1;
-               ve->event.newev = new + 1;
-               wake = 1;
-               ve->done = 1;
-       }
-       spin_unlock_irqrestore(&vt_event_lock, flags);
-       if (wake)
-               wake_up_interruptible(&vt_event_waitqueue);
-}
-
-/**
- *     vt_event_wait           -       wait for an event
- *     @vw: our event
- *
- *     Waits for an event to occur which completes our vt_event_wait
- *     structure. On return the structure has wv->done set to 1 for success
- *     or 0 if some event such as a signal ended the wait.
- */
-
-static void vt_event_wait(struct vt_event_wait *vw)
-{
-       unsigned long flags;
-       /* Prepare the event */
-       INIT_LIST_HEAD(&vw->list);
-       vw->done = 0;
-       /* Queue our event */
-       spin_lock_irqsave(&vt_event_lock, flags);
-       list_add(&vw->list, &vt_events);
-       spin_unlock_irqrestore(&vt_event_lock, flags);
-       /* Wait for it to pass */
-       wait_event_interruptible_tty(vt_event_waitqueue, vw->done);
-       /* Dequeue it */
-       spin_lock_irqsave(&vt_event_lock, flags);
-       list_del(&vw->list);
-       spin_unlock_irqrestore(&vt_event_lock, flags);
-}
-
-/**
- *     vt_event_wait_ioctl     -       event ioctl handler
- *     @arg: argument to ioctl
- *
- *     Implement the VT_WAITEVENT ioctl using the VT event interface
- */
-
-static int vt_event_wait_ioctl(struct vt_event __user *event)
-{
-       struct vt_event_wait vw;
-
-       if (copy_from_user(&vw.event, event, sizeof(struct vt_event)))
-               return -EFAULT;
-       /* Highest supported event for now */
-       if (vw.event.event & ~VT_MAX_EVENT)
-               return -EINVAL;
-
-       vt_event_wait(&vw);
-       /* If it occurred report it */
-       if (vw.done) {
-               if (copy_to_user(event, &vw.event, sizeof(struct vt_event)))
-                       return -EFAULT;
-               return 0;
-       }
-       return -EINTR;
-}
-
-/**
- *     vt_waitactive   -       active console wait
- *     @event: event code
- *     @n: new console
- *
- *     Helper for event waits. Used to implement the legacy
- *     event waiting ioctls in terms of events
- */
-
-int vt_waitactive(int n)
-{
-       struct vt_event_wait vw;
-       do {
-               if (n == fg_console + 1)
-                       break;
-               vw.event.event = VT_EVENT_SWITCH;
-               vt_event_wait(&vw);
-               if (vw.done == 0)
-                       return -EINTR;
-       } while (vw.event.newev != n);
-       return 0;
-}
-
-/*
- * these are the valid i/o ports we're allowed to change. they map all the
- * video ports
- */
-#define GPFIRST 0x3b4
-#define GPLAST 0x3df
-#define GPNUM (GPLAST - GPFIRST + 1)
-
-#define i (tmp.kb_index)
-#define s (tmp.kb_table)
-#define v (tmp.kb_value)
-static inline int
-do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd)
-{
-       struct kbentry tmp;
-       ushort *key_map, val, ov;
-
-       if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
-               return -EFAULT;
-
-       if (!capable(CAP_SYS_TTY_CONFIG))
-               perm = 0;
-
-       switch (cmd) {
-       case KDGKBENT:
-               key_map = key_maps[s];
-               if (key_map) {
-                   val = U(key_map[i]);
-                   if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
-                       val = K_HOLE;
-               } else
-                   val = (i ? K_HOLE : K_NOSUCHMAP);
-               return put_user(val, &user_kbe->kb_value);
-       case KDSKBENT:
-               if (!perm)
-                       return -EPERM;
-               if (!i && v == K_NOSUCHMAP) {
-                       /* deallocate map */
-                       key_map = key_maps[s];
-                       if (s && key_map) {
-                           key_maps[s] = NULL;
-                           if (key_map[0] == U(K_ALLOCATED)) {
-                                       kfree(key_map);
-                                       keymap_count--;
-                           }
-                       }
-                       break;
-               }
-
-               if (KTYP(v) < NR_TYPES) {
-                   if (KVAL(v) > max_vals[KTYP(v)])
-                               return -EINVAL;
-               } else
-                   if (kbd->kbdmode != VC_UNICODE)
-                               return -EINVAL;
-
-               /* ++Geert: non-PC keyboards may generate keycode zero */
-#if !defined(__mc68000__) && !defined(__powerpc__)
-               /* assignment to entry 0 only tests validity of args */
-               if (!i)
-                       break;
-#endif
-
-               if (!(key_map = key_maps[s])) {
-                       int j;
-
-                       if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
-                           !capable(CAP_SYS_RESOURCE))
-                               return -EPERM;
-
-                       key_map = kmalloc(sizeof(plain_map),
-                                                    GFP_KERNEL);
-                       if (!key_map)
-                               return -ENOMEM;
-                       key_maps[s] = key_map;
-                       key_map[0] = U(K_ALLOCATED);
-                       for (j = 1; j < NR_KEYS; j++)
-                               key_map[j] = U(K_HOLE);
-                       keymap_count++;
-               }
-               ov = U(key_map[i]);
-               if (v == ov)
-                       break;  /* nothing to do */
-               /*
-                * Attention Key.
-                */
-               if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               key_map[i] = U(v);
-               if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
-                       compute_shiftstate();
-               break;
-       }
-       return 0;
-}
-#undef i
-#undef s
-#undef v
-
-static inline int 
-do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm)
-{
-       struct kbkeycode tmp;
-       int kc = 0;
-
-       if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
-               return -EFAULT;
-       switch (cmd) {
-       case KDGETKEYCODE:
-               kc = getkeycode(tmp.scancode);
-               if (kc >= 0)
-                       kc = put_user(kc, &user_kbkc->keycode);
-               break;
-       case KDSETKEYCODE:
-               if (!perm)
-                       return -EPERM;
-               kc = setkeycode(tmp.scancode, tmp.keycode);
-               break;
-       }
-       return kc;
-}
-
-static inline int
-do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
-{
-       struct kbsentry *kbs;
-       char *p;
-       u_char *q;
-       u_char __user *up;
-       int sz;
-       int delta;
-       char *first_free, *fj, *fnw;
-       int i, j, k;
-       int ret;
-
-       if (!capable(CAP_SYS_TTY_CONFIG))
-               perm = 0;
-
-       kbs = kmalloc(sizeof(*kbs), GFP_KERNEL);
-       if (!kbs) {
-               ret = -ENOMEM;
-               goto reterr;
-       }
-
-       /* we mostly copy too much here (512bytes), but who cares ;) */
-       if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) {
-               ret = -EFAULT;
-               goto reterr;
-       }
-       kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
-       i = kbs->kb_func;
-
-       switch (cmd) {
-       case KDGKBSENT:
-               sz = sizeof(kbs->kb_string) - 1; /* sz should have been
-                                                 a struct member */
-               up = user_kdgkb->kb_string;
-               p = func_table[i];
-               if(p)
-                       for ( ; *p && sz; p++, sz--)
-                               if (put_user(*p, up++)) {
-                                       ret = -EFAULT;
-                                       goto reterr;
-                               }
-               if (put_user('\0', up)) {
-                       ret = -EFAULT;
-                       goto reterr;
-               }
-               kfree(kbs);
-               return ((p && *p) ? -EOVERFLOW : 0);
-       case KDSKBSENT:
-               if (!perm) {
-                       ret = -EPERM;
-                       goto reterr;
-               }
-
-               q = func_table[i];
-               first_free = funcbufptr + (funcbufsize - funcbufleft);
-               for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) 
-                       ;
-               if (j < MAX_NR_FUNC)
-                       fj = func_table[j];
-               else
-                       fj = first_free;
-
-               delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
-               if (delta <= funcbufleft) {     /* it fits in current buf */
-                   if (j < MAX_NR_FUNC) {
-                       memmove(fj + delta, fj, first_free - fj);
-                       for (k = j; k < MAX_NR_FUNC; k++)
-                           if (func_table[k])
-                               func_table[k] += delta;
-                   }
-                   if (!q)
-                     func_table[i] = fj;
-                   funcbufleft -= delta;
-               } else {                        /* allocate a larger buffer */
-                   sz = 256;
-                   while (sz < funcbufsize - funcbufleft + delta)
-                     sz <<= 1;
-                   fnw = kmalloc(sz, GFP_KERNEL);
-                   if(!fnw) {
-                     ret = -ENOMEM;
-                     goto reterr;
-                   }
-
-                   if (!q)
-                     func_table[i] = fj;
-                   if (fj > funcbufptr)
-                       memmove(fnw, funcbufptr, fj - funcbufptr);
-                   for (k = 0; k < j; k++)
-                     if (func_table[k])
-                       func_table[k] = fnw + (func_table[k] - funcbufptr);
-
-                   if (first_free > fj) {
-                       memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
-                       for (k = j; k < MAX_NR_FUNC; k++)
-                         if (func_table[k])
-                           func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
-                   }
-                   if (funcbufptr != func_buf)
-                     kfree(funcbufptr);
-                   funcbufptr = fnw;
-                   funcbufleft = funcbufleft - delta + sz - funcbufsize;
-                   funcbufsize = sz;
-               }
-               strcpy(func_table[i], kbs->kb_string);
-               break;
-       }
-       ret = 0;
-reterr:
-       kfree(kbs);
-       return ret;
-}
-
-static inline int 
-do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op)
-{
-       struct consolefontdesc cfdarg;
-       int i;
-
-       if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) 
-               return -EFAULT;
-       
-       switch (cmd) {
-       case PIO_FONTX:
-               if (!perm)
-                       return -EPERM;
-               op->op = KD_FONT_OP_SET;
-               op->flags = KD_FONT_FLAG_OLD;
-               op->width = 8;
-               op->height = cfdarg.charheight;
-               op->charcount = cfdarg.charcount;
-               op->data = cfdarg.chardata;
-               return con_font_op(vc_cons[fg_console].d, op);
-       case GIO_FONTX: {
-               op->op = KD_FONT_OP_GET;
-               op->flags = KD_FONT_FLAG_OLD;
-               op->width = 8;
-               op->height = cfdarg.charheight;
-               op->charcount = cfdarg.charcount;
-               op->data = cfdarg.chardata;
-               i = con_font_op(vc_cons[fg_console].d, op);
-               if (i)
-                       return i;
-               cfdarg.charheight = op->height;
-               cfdarg.charcount = op->charcount;
-               if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc)))
-                       return -EFAULT;
-               return 0;
-               }
-       }
-       return -EINVAL;
-}
-
-static inline int 
-do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_data *vc)
-{
-       struct unimapdesc tmp;
-
-       if (copy_from_user(&tmp, user_ud, sizeof tmp))
-               return -EFAULT;
-       if (tmp.entries)
-               if (!access_ok(VERIFY_WRITE, tmp.entries,
-                               tmp.entry_ct*sizeof(struct unipair)))
-                       return -EFAULT;
-       switch (cmd) {
-       case PIO_UNIMAP:
-               if (!perm)
-                       return -EPERM;
-               return con_set_unimap(vc, tmp.entry_ct, tmp.entries);
-       case GIO_UNIMAP:
-               if (!perm && fg_console != vc->vc_num)
-                       return -EPERM;
-               return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
-       }
-       return 0;
-}
-
-
-
-/*
- * We handle the console-specific ioctl's here.  We allow the
- * capability to modify any console, not just the fg_console. 
- */
-int vt_ioctl(struct tty_struct *tty, struct file * file,
-            unsigned int cmd, unsigned long arg)
-{
-       struct vc_data *vc = tty->driver_data;
-       struct console_font_op op;      /* used in multiple places here */
-       struct kbd_struct * kbd;
-       unsigned int console;
-       unsigned char ucval;
-       unsigned int uival;
-       void __user *up = (void __user *)arg;
-       int i, perm;
-       int ret = 0;
-
-       console = vc->vc_num;
-
-       tty_lock();
-
-       if (!vc_cons_allocated(console)) {      /* impossible? */
-               ret = -ENOIOCTLCMD;
-               goto out;
-       }
-
-
-       /*
-        * To have permissions to do most of the vt ioctls, we either have
-        * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
-        */
-       perm = 0;
-       if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
-               perm = 1;
-       kbd = kbd_table + console;
-       switch (cmd) {
-       case TIOCLINUX:
-               ret = tioclinux(tty, arg);
-               break;
-       case KIOCSOUND:
-               if (!perm)
-                       goto eperm;
-               /*
-                * The use of PIT_TICK_RATE is historic, it used to be
-                * the platform-dependent CLOCK_TICK_RATE between 2.6.12
-                * and 2.6.36, which was a minor but unfortunate ABI
-                * change.
-                */
-               if (arg)
-                       arg = PIT_TICK_RATE / arg;
-               kd_mksound(arg, 0);
-               break;
-
-       case KDMKTONE:
-               if (!perm)
-                       goto eperm;
-       {
-               unsigned int ticks, count;
-               
-               /*
-                * Generate the tone for the appropriate number of ticks.
-                * If the time is zero, turn off sound ourselves.
-                */
-               ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
-               count = ticks ? (arg & 0xffff) : 0;
-               if (count)
-                       count = PIT_TICK_RATE / count;
-               kd_mksound(count, ticks);
-               break;
-       }
-
-       case KDGKBTYPE:
-               /*
-                * this is naive.
-                */
-               ucval = KB_101;
-               goto setchar;
-
-               /*
-                * These cannot be implemented on any machine that implements
-                * ioperm() in user level (such as Alpha PCs) or not at all.
-                *
-                * XXX: you should never use these, just call ioperm directly..
-                */
-#ifdef CONFIG_X86
-       case KDADDIO:
-       case KDDELIO:
-               /*
-                * KDADDIO and KDDELIO may be able to add ports beyond what
-                * we reject here, but to be safe...
-                */
-               if (arg < GPFIRST || arg > GPLAST) {
-                       ret = -EINVAL;
-                       break;
-               }
-               ret = sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
-               break;
-
-       case KDENABIO:
-       case KDDISABIO:
-               ret = sys_ioperm(GPFIRST, GPNUM,
-                                 (cmd == KDENABIO)) ? -ENXIO : 0;
-               break;
-#endif
-
-       /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */
-               
-       case KDKBDREP:
-       {
-               struct kbd_repeat kbrep;
-               
-               if (!capable(CAP_SYS_TTY_CONFIG))
-                       goto eperm;
-
-               if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) {
-                       ret =  -EFAULT;
-                       break;
-               }
-               ret = kbd_rate(&kbrep);
-               if (ret)
-                       break;
-               if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat)))
-                       ret = -EFAULT;
-               break;
-       }
-
-       case KDSETMODE:
-               /*
-                * currently, setting the mode from KD_TEXT to KD_GRAPHICS
-                * doesn't do a whole lot. i'm not sure if it should do any
-                * restoration of modes or what...
-                *
-                * XXX It should at least call into the driver, fbdev's definitely
-                * need to restore their engine state. --BenH
-                */
-               if (!perm)
-                       goto eperm;
-               switch (arg) {
-               case KD_GRAPHICS:
-                       break;
-               case KD_TEXT0:
-               case KD_TEXT1:
-                       arg = KD_TEXT;
-               case KD_TEXT:
-                       break;
-               default:
-                       ret = -EINVAL;
-                       goto out;
-               }
-               if (vc->vc_mode == (unsigned char) arg)
-                       break;
-               vc->vc_mode = (unsigned char) arg;
-               if (console != fg_console)
-                       break;
-               /*
-                * explicitly blank/unblank the screen if switching modes
-                */
-               acquire_console_sem();
-               if (arg == KD_TEXT)
-                       do_unblank_screen(1);
-               else
-                       do_blank_screen(1);
-               release_console_sem();
-               break;
-
-       case KDGETMODE:
-               uival = vc->vc_mode;
-               goto setint;
-
-       case KDMAPDISP:
-       case KDUNMAPDISP:
-               /*
-                * these work like a combination of mmap and KDENABIO.
-                * this could be easily finished.
-                */
-               ret = -EINVAL;
-               break;
-
-       case KDSKBMODE:
-               if (!perm)
-                       goto eperm;
-               switch(arg) {
-                 case K_RAW:
-                       kbd->kbdmode = VC_RAW;
-                       break;
-                 case K_MEDIUMRAW:
-                       kbd->kbdmode = VC_MEDIUMRAW;
-                       break;
-                 case K_XLATE:
-                       kbd->kbdmode = VC_XLATE;
-                       compute_shiftstate();
-                       break;
-                 case K_UNICODE:
-                       kbd->kbdmode = VC_UNICODE;
-                       compute_shiftstate();
-                       break;
-                 default:
-                       ret = -EINVAL;
-                       goto out;
-               }
-               tty_ldisc_flush(tty);
-               break;
-
-       case KDGKBMODE:
-               uival = ((kbd->kbdmode == VC_RAW) ? K_RAW :
-                                (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
-                                (kbd->kbdmode == VC_UNICODE) ? K_UNICODE :
-                                K_XLATE);
-               goto setint;
-
-       /* this could be folded into KDSKBMODE, but for compatibility
-          reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
-       case KDSKBMETA:
-               switch(arg) {
-                 case K_METABIT:
-                       clr_vc_kbd_mode(kbd, VC_META);
-                       break;
-                 case K_ESCPREFIX:
-                       set_vc_kbd_mode(kbd, VC_META);
-                       break;
-                 default:
-                       ret = -EINVAL;
-               }
-               break;
-
-       case KDGKBMETA:
-               uival = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
-       setint:
-               ret = put_user(uival, (int __user *)arg);
-               break;
-
-       case KDGETKEYCODE:
-       case KDSETKEYCODE:
-               if(!capable(CAP_SYS_TTY_CONFIG))
-                       perm = 0;
-               ret = do_kbkeycode_ioctl(cmd, up, perm);
-               break;
-
-       case KDGKBENT:
-       case KDSKBENT:
-               ret = do_kdsk_ioctl(cmd, up, perm, kbd);
-               break;
-
-       case KDGKBSENT:
-       case KDSKBSENT:
-               ret = do_kdgkb_ioctl(cmd, up, perm);
-               break;
-
-       case KDGKBDIACR:
-       {
-               struct kbdiacrs __user *a = up;
-               struct kbdiacr diacr;
-               int i;
-
-               if (put_user(accent_table_size, &a->kb_cnt)) {
-                       ret = -EFAULT;
-                       break;
-               }
-               for (i = 0; i < accent_table_size; i++) {
-                       diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr);
-                       diacr.base = conv_uni_to_8bit(accent_table[i].base);
-                       diacr.result = conv_uni_to_8bit(accent_table[i].result);
-                       if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) {
-                               ret = -EFAULT;
-                               break;
-                       }
-               }
-               break;
-       }
-       case KDGKBDIACRUC:
-       {
-               struct kbdiacrsuc __user *a = up;
-
-               if (put_user(accent_table_size, &a->kb_cnt))
-                       ret = -EFAULT;
-               else if (copy_to_user(a->kbdiacruc, accent_table,
-                               accent_table_size*sizeof(struct kbdiacruc)))
-                       ret = -EFAULT;
-               break;
-       }
-
-       case KDSKBDIACR:
-       {
-               struct kbdiacrs __user *a = up;
-               struct kbdiacr diacr;
-               unsigned int ct;
-               int i;
-
-               if (!perm)
-                       goto eperm;
-               if (get_user(ct,&a->kb_cnt)) {
-                       ret = -EFAULT;
-                       break;
-               }
-               if (ct >= MAX_DIACR) {
-                       ret = -EINVAL;
-                       break;
-               }
-               accent_table_size = ct;
-               for (i = 0; i < ct; i++) {
-                       if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) {
-                               ret = -EFAULT;
-                               break;
-                       }
-                       accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr);
-                       accent_table[i].base = conv_8bit_to_uni(diacr.base);
-                       accent_table[i].result = conv_8bit_to_uni(diacr.result);
-               }
-               break;
-       }
-
-       case KDSKBDIACRUC:
-       {
-               struct kbdiacrsuc __user *a = up;
-               unsigned int ct;
-
-               if (!perm)
-                       goto eperm;
-               if (get_user(ct,&a->kb_cnt)) {
-                       ret = -EFAULT;
-                       break;
-               }
-               if (ct >= MAX_DIACR) {
-                       ret = -EINVAL;
-                       break;
-               }
-               accent_table_size = ct;
-               if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc)))
-                       ret = -EFAULT;
-               break;
-       }
-
-       /* the ioctls below read/set the flags usually shown in the leds */
-       /* don't use them - they will go away without warning */
-       case KDGKBLED:
-               ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
-               goto setchar;
-
-       case KDSKBLED:
-               if (!perm)
-                       goto eperm;
-               if (arg & ~0x77) {
-                       ret = -EINVAL;
-                       break;
-               }
-               kbd->ledflagstate = (arg & 7);
-               kbd->default_ledflagstate = ((arg >> 4) & 7);
-               set_leds();
-               break;
-
-       /* the ioctls below only set the lights, not the functions */
-       /* for those, see KDGKBLED and KDSKBLED above */
-       case KDGETLED:
-               ucval = getledstate();
-       setchar:
-               ret = put_user(ucval, (char __user *)arg);
-               break;
-
-       case KDSETLED:
-               if (!perm)
-                       goto eperm;
-               setledstate(kbd, arg);
-               break;
-
-       /*
-        * A process can indicate its willingness to accept signals
-        * generated by pressing an appropriate key combination.
-        * Thus, one can have a daemon that e.g. spawns a new console
-        * upon a keypress and then changes to it.
-        * See also the kbrequest field of inittab(5).
-        */
-       case KDSIGACCEPT:
-       {
-               if (!perm || !capable(CAP_KILL))
-                       goto eperm;
-               if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
-                       ret = -EINVAL;
-               else {
-                       spin_lock_irq(&vt_spawn_con.lock);
-                       put_pid(vt_spawn_con.pid);
-                       vt_spawn_con.pid = get_pid(task_pid(current));
-                       vt_spawn_con.sig = arg;
-                       spin_unlock_irq(&vt_spawn_con.lock);
-               }
-               break;
-       }
-
-       case VT_SETMODE:
-       {
-               struct vt_mode tmp;
-
-               if (!perm)
-                       goto eperm;
-               if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-               if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) {
-                       ret = -EINVAL;
-                       goto out;
-               }
-               acquire_console_sem();
-               vc->vt_mode = tmp;
-               /* the frsig is ignored, so we set it to 0 */
-               vc->vt_mode.frsig = 0;
-               put_pid(vc->vt_pid);
-               vc->vt_pid = get_pid(task_pid(current));
-               /* no switch is required -- saw@shade.msu.ru */
-               vc->vt_newvt = -1;
-               release_console_sem();
-               break;
-       }
-
-       case VT_GETMODE:
-       {
-               struct vt_mode tmp;
-               int rc;
-
-               acquire_console_sem();
-               memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode));
-               release_console_sem();
-
-               rc = copy_to_user(up, &tmp, sizeof(struct vt_mode));
-               if (rc)
-                       ret = -EFAULT;
-               break;
-       }
-
-       /*
-        * Returns global vt state. Note that VT 0 is always open, since
-        * it's an alias for the current VT, and people can't use it here.
-        * We cannot return state for more than 16 VTs, since v_state is short.
-        */
-       case VT_GETSTATE:
-       {
-               struct vt_stat __user *vtstat = up;
-               unsigned short state, mask;
-
-               if (put_user(fg_console + 1, &vtstat->v_active))
-                       ret = -EFAULT;
-               else {
-                       state = 1;      /* /dev/tty0 is always open */
-                       for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask;
-                                                       ++i, mask <<= 1)
-                               if (VT_IS_IN_USE(i))
-                                       state |= mask;
-                       ret = put_user(state, &vtstat->v_state);
-               }
-               break;
-       }
-
-       /*
-        * Returns the first available (non-opened) console.
-        */
-       case VT_OPENQRY:
-               for (i = 0; i < MAX_NR_CONSOLES; ++i)
-                       if (! VT_IS_IN_USE(i))
-                               break;
-               uival = i < MAX_NR_CONSOLES ? (i+1) : -1;
-               goto setint;             
-
-       /*
-        * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num,
-        * with num >= 1 (switches to vt 0, our console, are not allowed, just
-        * to preserve sanity).
-        */
-       case VT_ACTIVATE:
-               if (!perm)
-                       goto eperm;
-               if (arg == 0 || arg > MAX_NR_CONSOLES)
-                       ret =  -ENXIO;
-               else {
-                       arg--;
-                       acquire_console_sem();
-                       ret = vc_allocate(arg);
-                       release_console_sem();
-                       if (ret)
-                               break;
-                       set_console(arg);
-               }
-               break;
-
-       case VT_SETACTIVATE:
-       {
-               struct vt_setactivate vsa;
-
-               if (!perm)
-                       goto eperm;
-
-               if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg,
-                                       sizeof(struct vt_setactivate))) {
-                       ret = -EFAULT;
-                       goto out;
-               }
-               if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES)
-                       ret = -ENXIO;
-               else {
-                       vsa.console--;
-                       acquire_console_sem();
-                       ret = vc_allocate(vsa.console);
-                       if (ret == 0) {
-                               struct vc_data *nvc;
-                               /* This is safe providing we don't drop the
-                                  console sem between vc_allocate and
-                                  finishing referencing nvc */
-                               nvc = vc_cons[vsa.console].d;
-                               nvc->vt_mode = vsa.mode;
-                               nvc->vt_mode.frsig = 0;
-                               put_pid(nvc->vt_pid);
-                               nvc->vt_pid = get_pid(task_pid(current));
-                       }
-                       release_console_sem();
-                       if (ret)
-                               break;
-                       /* Commence switch and lock */
-                       set_console(arg);
-               }
-       }
-
-       /*
-        * wait until the specified VT has been activated
-        */
-       case VT_WAITACTIVE:
-               if (!perm)
-                       goto eperm;
-               if (arg == 0 || arg > MAX_NR_CONSOLES)
-                       ret = -ENXIO;
-               else
-                       ret = vt_waitactive(arg);
-               break;
-
-       /*
-        * If a vt is under process control, the kernel will not switch to it
-        * immediately, but postpone the operation until the process calls this
-        * ioctl, allowing the switch to complete.
-        *
-        * According to the X sources this is the behavior:
-        *      0:      pending switch-from not OK
-        *      1:      pending switch-from OK
-        *      2:      completed switch-to OK
-        */
-       case VT_RELDISP:
-               if (!perm)
-                       goto eperm;
-
-               if (vc->vt_mode.mode != VT_PROCESS) {
-                       ret = -EINVAL;
-                       break;
-               }
-               /*
-                * Switching-from response
-                */
-               acquire_console_sem();
-               if (vc->vt_newvt >= 0) {
-                       if (arg == 0)
-                               /*
-                                * Switch disallowed, so forget we were trying
-                                * to do it.
-                                */
-                               vc->vt_newvt = -1;
-
-                       else {
-                               /*
-                                * The current vt has been released, so
-                                * complete the switch.
-                                */
-                               int newvt;
-                               newvt = vc->vt_newvt;
-                               vc->vt_newvt = -1;
-                               ret = vc_allocate(newvt);
-                               if (ret) {
-                                       release_console_sem();
-                                       break;
-                               }
-                               /*
-                                * When we actually do the console switch,
-                                * make sure we are atomic with respect to
-                                * other console switches..
-                                */
-                               complete_change_console(vc_cons[newvt].d);
-                       }
-               } else {
-                       /*
-                        * Switched-to response
-                        */
-                       /*
-                        * If it's just an ACK, ignore it
-                        */
-                       if (arg != VT_ACKACQ)
-                               ret = -EINVAL;
-               }
-               release_console_sem();
-               break;
-
-        /*
-         * Disallocate memory associated to VT (but leave VT1)
-         */
-        case VT_DISALLOCATE:
-               if (arg > MAX_NR_CONSOLES) {
-                       ret = -ENXIO;
-                       break;
-               }
-               if (arg == 0) {
-                   /* deallocate all unused consoles, but leave 0 */
-                       acquire_console_sem();
-                       for (i=1; i<MAX_NR_CONSOLES; i++)
-                               if (! VT_BUSY(i))
-                                       vc_deallocate(i);
-                       release_console_sem();
-               } else {
-                       /* deallocate a single console, if possible */
-                       arg--;
-                       if (VT_BUSY(arg))
-                               ret = -EBUSY;
-                       else if (arg) {                       /* leave 0 */
-                               acquire_console_sem();
-                               vc_deallocate(arg);
-                               release_console_sem();
-                       }
-               }
-               break;
-
-       case VT_RESIZE:
-       {
-               struct vt_sizes __user *vtsizes = up;
-               struct vc_data *vc;
-
-               ushort ll,cc;
-               if (!perm)
-                       goto eperm;
-               if (get_user(ll, &vtsizes->v_rows) ||
-                   get_user(cc, &vtsizes->v_cols))
-                       ret = -EFAULT;
-               else {
-                       acquire_console_sem();
-                       for (i = 0; i < MAX_NR_CONSOLES; i++) {
-                               vc = vc_cons[i].d;
-
-                               if (vc) {
-                                       vc->vc_resize_user = 1;
-                                       vc_resize(vc_cons[i].d, cc, ll);
-                               }
-                       }
-                       release_console_sem();
-               }
-               break;
-       }
-
-       case VT_RESIZEX:
-       {
-               struct vt_consize __user *vtconsize = up;
-               ushort ll,cc,vlin,clin,vcol,ccol;
-               if (!perm)
-                       goto eperm;
-               if (!access_ok(VERIFY_READ, vtconsize,
-                               sizeof(struct vt_consize))) {
-                       ret = -EFAULT;
-                       break;
-               }
-               /* FIXME: Should check the copies properly */
-               __get_user(ll, &vtconsize->v_rows);
-               __get_user(cc, &vtconsize->v_cols);
-               __get_user(vlin, &vtconsize->v_vlin);
-               __get_user(clin, &vtconsize->v_clin);
-               __get_user(vcol, &vtconsize->v_vcol);
-               __get_user(ccol, &vtconsize->v_ccol);
-               vlin = vlin ? vlin : vc->vc_scan_lines;
-               if (clin) {
-                       if (ll) {
-                               if (ll != vlin/clin) {
-                                       /* Parameters don't add up */
-                                       ret = -EINVAL;
-                                       break;
-                               }
-                       } else 
-                               ll = vlin/clin;
-               }
-               if (vcol && ccol) {
-                       if (cc) {
-                               if (cc != vcol/ccol) {
-                                       ret = -EINVAL;
-                                       break;
-                               }
-                       } else
-                               cc = vcol/ccol;
-               }
-
-               if (clin > 32) {
-                       ret =  -EINVAL;
-                       break;
-               }
-                   
-               for (i = 0; i < MAX_NR_CONSOLES; i++) {
-                       if (!vc_cons[i].d)
-                               continue;
-                       acquire_console_sem();
-                       if (vlin)
-                               vc_cons[i].d->vc_scan_lines = vlin;
-                       if (clin)
-                               vc_cons[i].d->vc_font.height = clin;
-                       vc_cons[i].d->vc_resize_user = 1;
-                       vc_resize(vc_cons[i].d, cc, ll);
-                       release_console_sem();
-               }
-               break;
-       }
-
-       case PIO_FONT: {
-               if (!perm)
-                       goto eperm;
-               op.op = KD_FONT_OP_SET;
-               op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */
-               op.width = 8;
-               op.height = 0;
-               op.charcount = 256;
-               op.data = up;
-               ret = con_font_op(vc_cons[fg_console].d, &op);
-               break;
-       }
-
-       case GIO_FONT: {
-               op.op = KD_FONT_OP_GET;
-               op.flags = KD_FONT_FLAG_OLD;
-               op.width = 8;
-               op.height = 32;
-               op.charcount = 256;
-               op.data = up;
-               ret = con_font_op(vc_cons[fg_console].d, &op);
-               break;
-       }
-
-       case PIO_CMAP:
-                if (!perm)
-                       ret = -EPERM;
-               else
-                       ret = con_set_cmap(up);
-               break;
-
-       case GIO_CMAP:
-                ret = con_get_cmap(up);
-               break;
-
-       case PIO_FONTX:
-       case GIO_FONTX:
-               ret = do_fontx_ioctl(cmd, up, perm, &op);
-               break;
-
-       case PIO_FONTRESET:
-       {
-               if (!perm)
-                       goto eperm;
-
-#ifdef BROKEN_GRAPHICS_PROGRAMS
-               /* With BROKEN_GRAPHICS_PROGRAMS defined, the default
-                  font is not saved. */
-               ret = -ENOSYS;
-               break;
-#else
-               {
-               op.op = KD_FONT_OP_SET_DEFAULT;
-               op.data = NULL;
-               ret = con_font_op(vc_cons[fg_console].d, &op);
-               if (ret)
-                       break;
-               con_set_default_unimap(vc_cons[fg_console].d);
-               break;
-               }
-#endif
-       }
-
-       case KDFONTOP: {
-               if (copy_from_user(&op, up, sizeof(op))) {
-                       ret = -EFAULT;
-                       break;
-               }
-               if (!perm && op.op != KD_FONT_OP_GET)
-                       goto eperm;
-               ret = con_font_op(vc, &op);
-               if (ret)
-                       break;
-               if (copy_to_user(up, &op, sizeof(op)))
-                       ret = -EFAULT;
-               break;
-       }
-
-       case PIO_SCRNMAP:
-               if (!perm)
-                       ret = -EPERM;
-               else
-                       ret = con_set_trans_old(up);
-               break;
-
-       case GIO_SCRNMAP:
-               ret = con_get_trans_old(up);
-               break;
-
-       case PIO_UNISCRNMAP:
-               if (!perm)
-                       ret = -EPERM;
-               else
-                       ret = con_set_trans_new(up);
-               break;
-
-       case GIO_UNISCRNMAP:
-               ret = con_get_trans_new(up);
-               break;
-
-       case PIO_UNIMAPCLR:
-             { struct unimapinit ui;
-               if (!perm)
-                       goto eperm;
-               ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
-               if (ret)
-                       ret = -EFAULT;
-               else
-                       con_clear_unimap(vc, &ui);
-               break;
-             }
-
-       case PIO_UNIMAP:
-       case GIO_UNIMAP:
-               ret = do_unimap_ioctl(cmd, up, perm, vc);
-               break;
-
-       case VT_LOCKSWITCH:
-               if (!capable(CAP_SYS_TTY_CONFIG))
-                       goto eperm;
-               vt_dont_switch = 1;
-               break;
-       case VT_UNLOCKSWITCH:
-               if (!capable(CAP_SYS_TTY_CONFIG))
-                       goto eperm;
-               vt_dont_switch = 0;
-               break;
-       case VT_GETHIFONTMASK:
-               ret = put_user(vc->vc_hi_font_mask,
-                                       (unsigned short __user *)arg);
-               break;
-       case VT_WAITEVENT:
-               ret = vt_event_wait_ioctl((struct vt_event __user *)arg);
-               break;
-       default:
-               ret = -ENOIOCTLCMD;
-       }
-out:
-       tty_unlock();
-       return ret;
-eperm:
-       ret = -EPERM;
-       goto out;
-}
-
-void reset_vc(struct vc_data *vc)
-{
-       vc->vc_mode = KD_TEXT;
-       kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
-       vc->vt_mode.mode = VT_AUTO;
-       vc->vt_mode.waitv = 0;
-       vc->vt_mode.relsig = 0;
-       vc->vt_mode.acqsig = 0;
-       vc->vt_mode.frsig = 0;
-       put_pid(vc->vt_pid);
-       vc->vt_pid = NULL;
-       vc->vt_newvt = -1;
-       if (!in_interrupt())    /* Via keyboard.c:SAK() - akpm */
-               reset_palette(vc);
-}
-
-void vc_SAK(struct work_struct *work)
-{
-       struct vc *vc_con =
-               container_of(work, struct vc, SAK_work);
-       struct vc_data *vc;
-       struct tty_struct *tty;
-
-       acquire_console_sem();
-       vc = vc_con->d;
-       if (vc) {
-               tty = vc->port.tty;
-               /*
-                * SAK should also work in all raw modes and reset
-                * them properly.
-                */
-               if (tty)
-                       __do_SAK(tty);
-               reset_vc(vc);
-       }
-       release_console_sem();
-}
-
-#ifdef CONFIG_COMPAT
-
-struct compat_consolefontdesc {
-       unsigned short charcount;       /* characters in font (256 or 512) */
-       unsigned short charheight;      /* scan lines per character (1-32) */
-       compat_caddr_t chardata;        /* font data in expanded form */
-};
-
-static inline int
-compat_fontx_ioctl(int cmd, struct compat_consolefontdesc __user *user_cfd,
-                        int perm, struct console_font_op *op)
-{
-       struct compat_consolefontdesc cfdarg;
-       int i;
-
-       if (copy_from_user(&cfdarg, user_cfd, sizeof(struct compat_consolefontdesc)))
-               return -EFAULT;
-
-       switch (cmd) {
-       case PIO_FONTX:
-               if (!perm)
-                       return -EPERM;
-               op->op = KD_FONT_OP_SET;
-               op->flags = KD_FONT_FLAG_OLD;
-               op->width = 8;
-               op->height = cfdarg.charheight;
-               op->charcount = cfdarg.charcount;
-               op->data = compat_ptr(cfdarg.chardata);
-               return con_font_op(vc_cons[fg_console].d, op);
-       case GIO_FONTX:
-               op->op = KD_FONT_OP_GET;
-               op->flags = KD_FONT_FLAG_OLD;
-               op->width = 8;
-               op->height = cfdarg.charheight;
-               op->charcount = cfdarg.charcount;
-               op->data = compat_ptr(cfdarg.chardata);
-               i = con_font_op(vc_cons[fg_console].d, op);
-               if (i)
-                       return i;
-               cfdarg.charheight = op->height;
-               cfdarg.charcount = op->charcount;
-               if (copy_to_user(user_cfd, &cfdarg, sizeof(struct compat_consolefontdesc)))
-                       return -EFAULT;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-struct compat_console_font_op {
-       compat_uint_t op;        /* operation code KD_FONT_OP_* */
-       compat_uint_t flags;     /* KD_FONT_FLAG_* */
-       compat_uint_t width, height;     /* font size */
-       compat_uint_t charcount;
-       compat_caddr_t data;    /* font data with height fixed to 32 */
-};
-
-static inline int
-compat_kdfontop_ioctl(struct compat_console_font_op __user *fontop,
-                        int perm, struct console_font_op *op, struct vc_data *vc)
-{
-       int i;
-
-       if (copy_from_user(op, fontop, sizeof(struct compat_console_font_op)))
-               return -EFAULT;
-       if (!perm && op->op != KD_FONT_OP_GET)
-               return -EPERM;
-       op->data = compat_ptr(((struct compat_console_font_op *)op)->data);
-       op->flags |= KD_FONT_FLAG_OLD;
-       i = con_font_op(vc, op);
-       if (i)
-               return i;
-       ((struct compat_console_font_op *)op)->data = (unsigned long)op->data;
-       if (copy_to_user(fontop, op, sizeof(struct compat_console_font_op)))
-               return -EFAULT;
-       return 0;
-}
-
-struct compat_unimapdesc {
-       unsigned short entry_ct;
-       compat_caddr_t entries;
-};
-
-static inline int
-compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud,
-                        int perm, struct vc_data *vc)
-{
-       struct compat_unimapdesc tmp;
-       struct unipair __user *tmp_entries;
-
-       if (copy_from_user(&tmp, user_ud, sizeof tmp))
-               return -EFAULT;
-       tmp_entries = compat_ptr(tmp.entries);
-       if (tmp_entries)
-               if (!access_ok(VERIFY_WRITE, tmp_entries,
-                               tmp.entry_ct*sizeof(struct unipair)))
-                       return -EFAULT;
-       switch (cmd) {
-       case PIO_UNIMAP:
-               if (!perm)
-                       return -EPERM;
-               return con_set_unimap(vc, tmp.entry_ct, tmp_entries);
-       case GIO_UNIMAP:
-               if (!perm && fg_console != vc->vc_num)
-                       return -EPERM;
-               return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp_entries);
-       }
-       return 0;
-}
-
-long vt_compat_ioctl(struct tty_struct *tty, struct file * file,
-            unsigned int cmd, unsigned long arg)
-{
-       struct vc_data *vc = tty->driver_data;
-       struct console_font_op op;      /* used in multiple places here */
-       struct kbd_struct *kbd;
-       unsigned int console;
-       void __user *up = (void __user *)arg;
-       int perm;
-       int ret = 0;
-
-       console = vc->vc_num;
-
-       tty_lock();
-
-       if (!vc_cons_allocated(console)) {      /* impossible? */
-               ret = -ENOIOCTLCMD;
-               goto out;
-       }
-
-       /*
-        * To have permissions to do most of the vt ioctls, we either have
-        * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
-        */
-       perm = 0;
-       if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
-               perm = 1;
-
-       kbd = kbd_table + console;
-       switch (cmd) {
-       /*
-        * these need special handlers for incompatible data structures
-        */
-       case PIO_FONTX:
-       case GIO_FONTX:
-               ret = compat_fontx_ioctl(cmd, up, perm, &op);
-               break;
-
-       case KDFONTOP:
-               ret = compat_kdfontop_ioctl(up, perm, &op, vc);
-               break;
-
-       case PIO_UNIMAP:
-       case GIO_UNIMAP:
-               ret = compat_unimap_ioctl(cmd, up, perm, vc);
-               break;
-
-       /*
-        * all these treat 'arg' as an integer
-        */
-       case KIOCSOUND:
-       case KDMKTONE:
-#ifdef CONFIG_X86
-       case KDADDIO:
-       case KDDELIO:
-#endif
-       case KDSETMODE:
-       case KDMAPDISP:
-       case KDUNMAPDISP:
-       case KDSKBMODE:
-       case KDSKBMETA:
-       case KDSKBLED:
-       case KDSETLED:
-       case KDSIGACCEPT:
-       case VT_ACTIVATE:
-       case VT_WAITACTIVE:
-       case VT_RELDISP:
-       case VT_DISALLOCATE:
-       case VT_RESIZE:
-       case VT_RESIZEX:
-               goto fallback;
-
-       /*
-        * the rest has a compatible data structure behind arg,
-        * but we have to convert it to a proper 64 bit pointer.
-        */
-       default:
-               arg = (unsigned long)compat_ptr(arg);
-               goto fallback;
-       }
-out:
-       tty_unlock();
-       return ret;
-
-fallback:
-       tty_unlock();
-       return vt_ioctl(tty, file, cmd, arg);
-}
-
-
-#endif /* CONFIG_COMPAT */
-
-
-/*
- * Performs the back end of a vt switch. Called under the console
- * semaphore.
- */
-static void complete_change_console(struct vc_data *vc)
-{
-       unsigned char old_vc_mode;
-       int old = fg_console;
-
-       last_console = fg_console;
-
-       /*
-        * If we're switching, we could be going from KD_GRAPHICS to
-        * KD_TEXT mode or vice versa, which means we need to blank or
-        * unblank the screen later.
-        */
-       old_vc_mode = vc_cons[fg_console].d->vc_mode;
-       switch_screen(vc);
-
-       /*
-        * This can't appear below a successful kill_pid().  If it did,
-        * then the *blank_screen operation could occur while X, having
-        * received acqsig, is waking up on another processor.  This
-        * condition can lead to overlapping accesses to the VGA range
-        * and the framebuffer (causing system lockups).
-        *
-        * To account for this we duplicate this code below only if the
-        * controlling process is gone and we've called reset_vc.
-        */
-       if (old_vc_mode != vc->vc_mode) {
-               if (vc->vc_mode == KD_TEXT)
-                       do_unblank_screen(1);
-               else
-                       do_blank_screen(1);
-       }
-
-       /*
-        * If this new console is under process control, send it a signal
-        * telling it that it has acquired. Also check if it has died and
-        * clean up (similar to logic employed in change_console())
-        */
-       if (vc->vt_mode.mode == VT_PROCESS) {
-               /*
-                * Send the signal as privileged - kill_pid() will
-                * tell us if the process has gone or something else
-                * is awry
-                */
-               if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) {
-               /*
-                * The controlling process has died, so we revert back to
-                * normal operation. In this case, we'll also change back
-                * to KD_TEXT mode. I'm not sure if this is strictly correct
-                * but it saves the agony when the X server dies and the screen
-                * remains blanked due to KD_GRAPHICS! It would be nice to do
-                * this outside of VT_PROCESS but there is no single process
-                * to account for and tracking tty count may be undesirable.
-                */
-                       reset_vc(vc);
-
-                       if (old_vc_mode != vc->vc_mode) {
-                               if (vc->vc_mode == KD_TEXT)
-                                       do_unblank_screen(1);
-                               else
-                                       do_blank_screen(1);
-                       }
-               }
-       }
-
-       /*
-        * Wake anyone waiting for their VT to activate
-        */
-       vt_event_post(VT_EVENT_SWITCH, old, vc->vc_num);
-       return;
-}
-
-/*
- * Performs the front-end of a vt switch
- */
-void change_console(struct vc_data *new_vc)
-{
-       struct vc_data *vc;
-
-       if (!new_vc || new_vc->vc_num == fg_console || vt_dont_switch)
-               return;
-
-       /*
-        * If this vt is in process mode, then we need to handshake with
-        * that process before switching. Essentially, we store where that
-        * vt wants to switch to and wait for it to tell us when it's done
-        * (via VT_RELDISP ioctl).
-        *
-        * We also check to see if the controlling process still exists.
-        * If it doesn't, we reset this vt to auto mode and continue.
-        * This is a cheap way to track process control. The worst thing
-        * that can happen is: we send a signal to a process, it dies, and
-        * the switch gets "lost" waiting for a response; hopefully, the
-        * user will try again, we'll detect the process is gone (unless
-        * the user waits just the right amount of time :-) and revert the
-        * vt to auto control.
-        */
-       vc = vc_cons[fg_console].d;
-       if (vc->vt_mode.mode == VT_PROCESS) {
-               /*
-                * Send the signal as privileged - kill_pid() will
-                * tell us if the process has gone or something else
-                * is awry.
-                *
-                * We need to set vt_newvt *before* sending the signal or we
-                * have a race.
-                */
-               vc->vt_newvt = new_vc->vc_num;
-               if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {
-                       /*
-                        * It worked. Mark the vt to switch to and
-                        * return. The process needs to send us a
-                        * VT_RELDISP ioctl to complete the switch.
-                        */
-                       return;
-               }
-
-               /*
-                * The controlling process has died, so we revert back to
-                * normal operation. In this case, we'll also change back
-                * to KD_TEXT mode. I'm not sure if this is strictly correct
-                * but it saves the agony when the X server dies and the screen
-                * remains blanked due to KD_GRAPHICS! It would be nice to do
-                * this outside of VT_PROCESS but there is no single process
-                * to account for and tracking tty count may be undesirable.
-                */
-               reset_vc(vc);
-
-               /*
-                * Fall through to normal (VT_AUTO) handling of the switch...
-                */
-       }
-
-       /*
-        * Ignore all switches in KD_GRAPHICS+VT_AUTO mode
-        */
-       if (vc->vc_mode == KD_GRAPHICS)
-               return;
-
-       complete_change_console(new_vc);
-}
-
-/* Perform a kernel triggered VT switch for suspend/resume */
-
-static int disable_vt_switch;
-
-int vt_move_to_console(unsigned int vt, int alloc)
-{
-       int prev;
-
-       acquire_console_sem();
-       /* Graphics mode - up to X */
-       if (disable_vt_switch) {
-               release_console_sem();
-               return 0;
-       }
-       prev = fg_console;
-
-       if (alloc && vc_allocate(vt)) {
-               /* we can't have a free VC for now. Too bad,
-                * we don't want to mess the screen for now. */
-               release_console_sem();
-               return -ENOSPC;
-       }
-
-       if (set_console(vt)) {
-               /*
-                * We're unable to switch to the SUSPEND_CONSOLE.
-                * Let the calling function know so it can decide
-                * what to do.
-                */
-               release_console_sem();
-               return -EIO;
-       }
-       release_console_sem();
-       tty_lock();
-       if (vt_waitactive(vt + 1)) {
-               pr_debug("Suspend: Can't switch VCs.");
-               tty_unlock();
-               return -EINTR;
-       }
-       tty_unlock();
-       return prev;
-}
-
-/*
- * Normally during a suspend, we allocate a new console and switch to it.
- * When we resume, we switch back to the original console.  This switch
- * can be slow, so on systems where the framebuffer can handle restoration
- * of video registers anyways, there's little point in doing the console
- * switch.  This function allows you to disable it by passing it '0'.
- */
-void pm_set_vt_switch(int do_switch)
-{
-       acquire_console_sem();
-       disable_vt_switch = !do_switch;
-       release_console_sem();
-}
-EXPORT_SYMBOL(pm_set_vt_switch);
index a44611652282c6c173e70b861910d4bee1610db4..d68d3aa1814b4ac635017e98cebd9625b0e7b40a 100644 (file)
@@ -616,13 +616,9 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
        /* get hold of clock */
        p->clk = clk_get(&p->pdev->dev, "cmt_fck");
        if (IS_ERR(p->clk)) {
-               dev_warn(&p->pdev->dev, "using deprecated clock lookup\n");
-               p->clk = clk_get(&p->pdev->dev, cfg->clk);
-               if (IS_ERR(p->clk)) {
-                       dev_err(&p->pdev->dev, "cannot get clock\n");
-                       ret = PTR_ERR(p->clk);
-                       goto err1;
-               }
+               dev_err(&p->pdev->dev, "cannot get clock\n");
+               ret = PTR_ERR(p->clk);
+               goto err1;
        }
 
        if (resource_size(res) == 6) {
index ef7a5be8a09f5a36bb1ed545fccf64e2fa7e7f89..40630cb9823707423c84e2459b812165786c5a15 100644 (file)
@@ -287,13 +287,9 @@ static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev)
        /* get hold of clock */
        p->clk = clk_get(&p->pdev->dev, "mtu2_fck");
        if (IS_ERR(p->clk)) {
-               dev_warn(&p->pdev->dev, "using deprecated clock lookup\n");
-               p->clk = clk_get(&p->pdev->dev, cfg->clk);
-               if (IS_ERR(p->clk)) {
-                       dev_err(&p->pdev->dev, "cannot get clock\n");
-                       ret = PTR_ERR(p->clk);
-                       goto err1;
-               }
+               dev_err(&p->pdev->dev, "cannot get clock\n");
+               ret = PTR_ERR(p->clk);
+               goto err1;
        }
 
        return sh_mtu2_register(p, (char *)dev_name(&p->pdev->dev),
index de715901b82a28a09f8160dd1b62f17a25247a51..36aba9923060f5dfbd02d250a1de675e274e7695 100644 (file)
@@ -393,13 +393,9 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)
        /* get hold of clock */
        p->clk = clk_get(&p->pdev->dev, "tmu_fck");
        if (IS_ERR(p->clk)) {
-               dev_warn(&p->pdev->dev, "using deprecated clock lookup\n");
-               p->clk = clk_get(&p->pdev->dev, cfg->clk);
-               if (IS_ERR(p->clk)) {
-                       dev_err(&p->pdev->dev, "cannot get clock\n");
-                       ret = PTR_ERR(p->clk);
-                       goto err1;
-               }
+               dev_err(&p->pdev->dev, "cannot get clock\n");
+               ret = PTR_ERR(p->clk);
+               goto err1;
        }
 
        return sh_tmu_register(p, (char *)dev_name(&p->pdev->dev),
index 9dcb17d51aee737bcbb4ac478807c04311588d6c..84eb607d6c031b4275e834604d4c0c0729fa8502 100644 (file)
@@ -577,17 +577,11 @@ static int ohci_update_phy_reg(struct fw_card *card, int addr,
        return ret;
 }
 
-static int ar_context_add_page(struct ar_context *ctx)
+static void ar_context_link_page(struct ar_context *ctx,
+                                struct ar_buffer *ab, dma_addr_t ab_bus)
 {
-       struct device *dev = ctx->ohci->card.device;
-       struct ar_buffer *ab;
-       dma_addr_t uninitialized_var(ab_bus);
        size_t offset;
 
-       ab = dma_alloc_coherent(dev, PAGE_SIZE, &ab_bus, GFP_ATOMIC);
-       if (ab == NULL)
-               return -ENOMEM;
-
        ab->next = NULL;
        memset(&ab->descriptor, 0, sizeof(ab->descriptor));
        ab->descriptor.control        = cpu_to_le16(DESCRIPTOR_INPUT_MORE |
@@ -606,6 +600,19 @@ static int ar_context_add_page(struct ar_context *ctx)
 
        reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
        flush_writes(ctx->ohci);
+}
+
+static int ar_context_add_page(struct ar_context *ctx)
+{
+       struct device *dev = ctx->ohci->card.device;
+       struct ar_buffer *ab;
+       dma_addr_t uninitialized_var(ab_bus);
+
+       ab = dma_alloc_coherent(dev, PAGE_SIZE, &ab_bus, GFP_ATOMIC);
+       if (ab == NULL)
+               return -ENOMEM;
+
+       ar_context_link_page(ctx, ab, ab_bus);
 
        return 0;
 }
@@ -730,16 +737,17 @@ static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer)
 static void ar_context_tasklet(unsigned long data)
 {
        struct ar_context *ctx = (struct ar_context *)data;
-       struct fw_ohci *ohci = ctx->ohci;
        struct ar_buffer *ab;
        struct descriptor *d;
        void *buffer, *end;
+       __le16 res_count;
 
        ab = ctx->current_buffer;
        d = &ab->descriptor;
 
-       if (d->res_count == 0) {
-               size_t size, rest, offset;
+       res_count = ACCESS_ONCE(d->res_count);
+       if (res_count == 0) {
+               size_t size, size2, rest, pktsize, size3, offset;
                dma_addr_t start_bus;
                void *start;
 
@@ -750,29 +758,63 @@ static void ar_context_tasklet(unsigned long data)
                 */
 
                offset = offsetof(struct ar_buffer, data);
-               start = buffer = ab;
+               start = ab;
                start_bus = le32_to_cpu(ab->descriptor.data_address) - offset;
+               buffer = ab->data;
 
                ab = ab->next;
                d = &ab->descriptor;
-               size = buffer + PAGE_SIZE - ctx->pointer;
+               size = start + PAGE_SIZE - ctx->pointer;
+               /* valid buffer data in the next page */
                rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count);
+               /* what actually fits in this page */
+               size2 = min(rest, (size_t)PAGE_SIZE - offset - size);
                memmove(buffer, ctx->pointer, size);
-               memcpy(buffer + size, ab->data, rest);
-               ctx->current_buffer = ab;
-               ctx->pointer = (void *) ab->data + rest;
-               end = buffer + size + rest;
+               memcpy(buffer + size, ab->data, size2);
+
+               while (size > 0) {
+                       void *next = handle_ar_packet(ctx, buffer);
+                       pktsize = next - buffer;
+                       if (pktsize >= size) {
+                               /*
+                                * We have handled all the data that was
+                                * originally in this page, so we can now
+                                * continue in the next page.
+                                */
+                               buffer = next;
+                               break;
+                       }
+                       /* move the next packet to the start of the buffer */
+                       memmove(buffer, next, size + size2 - pktsize);
+                       size -= pktsize;
+                       /* fill up this page again */
+                       size3 = min(rest - size2,
+                                   (size_t)PAGE_SIZE - offset - size - size2);
+                       memcpy(buffer + size + size2,
+                              (void *) ab->data + size2, size3);
+                       size2 += size3;
+               }
 
-               while (buffer < end)
-                       buffer = handle_ar_packet(ctx, buffer);
+               if (rest > 0) {
+                       /* handle the packets that are fully in the next page */
+                       buffer = (void *) ab->data +
+                                       (buffer - (start + offset + size));
+                       end = (void *) ab->data + rest;
+
+                       while (buffer < end)
+                               buffer = handle_ar_packet(ctx, buffer);
 
-               dma_free_coherent(ohci->card.device, PAGE_SIZE,
-                                 start, start_bus);
-               ar_context_add_page(ctx);
+                       ctx->current_buffer = ab;
+                       ctx->pointer = end;
+
+                       ar_context_link_page(ctx, start, start_bus);
+               } else {
+                       ctx->pointer = start + PAGE_SIZE;
+               }
        } else {
                buffer = ctx->pointer;
                ctx->pointer = end =
-                       (void *) ab + PAGE_SIZE - le16_to_cpu(d->res_count);
+                       (void *) ab + PAGE_SIZE - le16_to_cpu(res_count);
 
                while (buffer < end)
                        buffer = handle_ar_packet(ctx, buffer);
index 267626178678363882ad14d01e96122ccfbfe2d2..4b50601027d3f4787249651c8d58da5126603f12 100644 (file)
@@ -82,7 +82,7 @@ static struct ltc4261_data *ltc4261_update_device(struct device *dev)
                        val = i2c_smbus_read_byte_data(client, i);
                        if (unlikely(val < 0)) {
                                dev_dbg(dev,
-                                       "Failed to read ADC value: error %d",
+                                       "Failed to read ADC value: error %d\n",
                                        val);
                                ret = ERR_PTR(val);
                                goto abort;
@@ -230,8 +230,7 @@ static int ltc4261_probe(struct i2c_client *client,
                return -ENODEV;
 
        if (i2c_smbus_read_byte_data(client, LTC4261_STATUS) < 0) {
-               dev_err(&client->dev, "Failed to read register %d:%02x:%02x\n",
-                       adapter->id, client->addr, LTC4261_STATUS);
+               dev_err(&client->dev, "Failed to read status register\n");
                return -ENODEV;
        }
 
index 40b914bded8c2a3237abca74d295d8d80a02b2e3..2e72227bd071b9d18329e60a0e4b06a444700ec9 100644 (file)
@@ -1427,8 +1427,8 @@ modeisar(struct BCState *bcs, int mode, int bc)
                                        &bcs->hw.isar.reg->Flags))
                                        bcs->hw.isar.dpath = 1;
                                else {
-                                       printk(KERN_WARNING"isar modeisar analog funktions only with DP1\n");
-                                       debugl1(cs, "isar modeisar analog funktions only with DP1");
+                                       printk(KERN_WARNING"isar modeisar analog functions only with DP1\n");
+                                       debugl1(cs, "isar modeisar analog functions only with DP1");
                                        return(1);
                                }
                                break;
index 3063f591f0dca0e0eb809bb4b490039d8bcf2943..1739557a903881a246c14d5047cca5a454081894 100644 (file)
@@ -92,3 +92,5 @@ unmap:
 }
 
 arch_initcall(soekris_init);
+
+MODULE_LICENSE("GPL");
index 43579b3b24acce4e23caac9e9ce1d2f2f811af44..53363108994ee93bed670940b0eb91170a389456 100644 (file)
@@ -3043,7 +3043,6 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
        atl1_pcie_patch(adapter);
        /* assume we have no link for now */
        netif_carrier_off(netdev);
-       netif_stop_queue(netdev);
 
        setup_timer(&adapter->phy_config_timer, atl1_phy_config,
                    (unsigned long)adapter);
index 9eea225decaf724e7d88243fc8c462c62020f81e..863e73a85fbe0ef4cd48ebac5cd5e95846397ebc 100644 (file)
@@ -20,8 +20,8 @@
  * (you will need to reboot afterwards) */
 /* #define BNX2X_STOP_ON_ERROR */
 
-#define DRV_MODULE_VERSION      "1.60.00-3"
-#define DRV_MODULE_RELDATE      "2010/10/19"
+#define DRV_MODULE_VERSION      "1.60.00-4"
+#define DRV_MODULE_RELDATE      "2010/11/01"
 #define BNX2X_BC_VER            0x040200
 
 #define BNX2X_MULTI_QUEUE
index 18c8e23a0e82fafaabe0183700960a194c9524af..4cfd4e9b5586f1740d547b02aa8f86e756c86033 100644 (file)
@@ -244,7 +244,14 @@ struct port_hw_cfg {                           /* port 0: 0x12c  port 1: 0x2bc */
 
        u16 xgxs_config_tx[4];                              /* 0x1A0 */
 
-       u32 Reserved1[57];                                  /* 0x1A8 */
+       u32 Reserved1[56];                                  /* 0x1A8 */
+       u32 default_cfg;                                    /* 0x288 */
+       /*  Enable BAM on KR */
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_MASK                    0x00100000
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_SHIFT                   20
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_DISABLED                0x00000000
+#define PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED                 0x00100000
+
        u32 speed_capability_mask2;                         /* 0x28C */
 #define PORT_HW_CFG_SPEED_CAPABILITY2_D3_MASK                0x0000FFFF
 #define PORT_HW_CFG_SPEED_CAPABILITY2_D3_SHIFT               0
index 2326774df843841315d783dfa6c53a073a2ef4b5..580919619252e3d0594f5365226bc295a8efcba9 100644 (file)
@@ -610,7 +610,7 @@ static u8 bnx2x_bmac_enable(struct link_params *params,
        /* reset and unreset the BigMac */
        REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR,
                     (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
-       udelay(10);
+       msleep(1);
 
        REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET,
                     (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port));
@@ -3525,13 +3525,19 @@ static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
        DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1);
 
        /* Enable CL37 BAM */
-       bnx2x_cl45_read(bp, phy,
-                       MDIO_AN_DEVAD,
-                       MDIO_AN_REG_8073_BAM, &val);
-       bnx2x_cl45_write(bp, phy,
-                        MDIO_AN_DEVAD,
-                        MDIO_AN_REG_8073_BAM, val | 1);
+       if (REG_RD(bp, params->shmem_base +
+                        offsetof(struct shmem_region, dev_info.
+                                 port_hw_config[params->port].default_cfg)) &
+           PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED) {
 
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_AN_DEVAD,
+                               MDIO_AN_REG_8073_BAM, &val);
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_AN_DEVAD,
+                                MDIO_AN_REG_8073_BAM, val | 1);
+               DP(NETIF_MSG_LINK, "Enable CL37 BAM on KR\n");
+       }
        if (params->loopback_mode == LOOPBACK_EXT) {
                bnx2x_807x_force_10G(bp, phy);
                DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n");
@@ -5302,7 +5308,7 @@ static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
 {
        struct bnx2x *bp = params->bp;
        u16 autoneg_val, an_1000_val, an_10_100_val;
-       bnx2x_wait_reset_complete(bp, phy);
+
        bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4,
                      1 << NIG_LATCH_BC_ENABLE_MI_INT);
 
@@ -5431,6 +5437,7 @@ static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy,
 
        /* HW reset */
        bnx2x_ext_phy_hw_reset(bp, params->port);
+       bnx2x_wait_reset_complete(bp, phy);
 
        bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
        return bnx2x_848xx_cmn_config_init(phy, params, vars);
@@ -5441,7 +5448,7 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
                                  struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
-       u8 port = params->port, initialize = 1;
+       u8 port, initialize = 1;
        u16 val;
        u16 temp;
        u32 actual_phy_selection;
@@ -5450,11 +5457,16 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
        /* This is just for MDIO_CTL_REG_84823_MEDIA register. */
 
        msleep(1);
+       if (CHIP_IS_E2(bp))
+               port = BP_PATH(bp);
+       else
+               port = params->port;
        bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
                       MISC_REGISTERS_GPIO_OUTPUT_HIGH,
                       port);
-       msleep(200); /* 100 is not enough */
-
+       bnx2x_wait_reset_complete(bp, phy);
+       /* Wait for GPHY to come out of reset */
+       msleep(50);
        /* BCM84823 requires that XGXS links up first @ 10G for normal
        behavior */
        temp = vars->line_speed;
@@ -5625,7 +5637,11 @@ static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
                                   struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
-       u8 port = params->port;
+       u8 port;
+       if (CHIP_IS_E2(bp))
+               port = BP_PATH(bp);
+       else
+               port = params->port;
        bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
                            MISC_REGISTERS_GPIO_OUTPUT_LOW,
                            port);
@@ -6928,7 +6944,7 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
                  u8 reset_ext_phy)
 {
        struct bnx2x *bp = params->bp;
-       u8 phy_index, port = params->port;
+       u8 phy_index, port = params->port, clear_latch_ind = 0;
        DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port);
        /* disable attentions */
        vars->link_status = 0;
@@ -6966,9 +6982,18 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
                                params->phy[phy_index].link_reset(
                                        &params->phy[phy_index],
                                        params);
+                       if (params->phy[phy_index].flags &
+                           FLAGS_REARM_LATCH_SIGNAL)
+                               clear_latch_ind = 1;
                }
        }
 
+       if (clear_latch_ind) {
+               /* Clear latching indication */
+               bnx2x_rearm_latch_signal(bp, port, 0);
+               bnx2x_bits_dis(bp, NIG_REG_LATCH_BC_0 + port*4,
+                              1 << NIG_LATCH_BC_ENABLE_MI_INT);
+       }
        if (params->phy[INT_PHY].link_reset)
                params->phy[INT_PHY].link_reset(
                        &params->phy[INT_PHY], params);
@@ -6999,6 +7024,7 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
        s8 port;
        s8 port_of_path = 0;
 
+       bnx2x_ext_phy_hw_reset(bp, 0);
        /* PART1 - Reset both phys */
        for (port = PORT_MAX - 1; port >= PORT_0; port--) {
                u32 shmem_base, shmem2_base;
@@ -7021,7 +7047,8 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
                        return -EINVAL;
                }
                /* disable attentions */
-               bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4,
+               bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
+                              port_of_path*4,
                             (NIG_MASK_XGXS0_LINK_STATUS |
                              NIG_MASK_XGXS0_LINK10G |
                              NIG_MASK_SERDES0_LINK_STATUS |
@@ -7132,7 +7159,7 @@ static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp,
                (1<<(MISC_REGISTERS_GPIO_3 + MISC_REGISTERS_GPIO_PORT_SHIFT)));
        REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
 
-       bnx2x_ext_phy_hw_reset(bp, 1);
+       bnx2x_ext_phy_hw_reset(bp, 0);
        msleep(5);
        for (port = 0; port < PORT_MAX; port++) {
                u32 shmem_base, shmem2_base;
index 8427533fe313c35cb38727e533cd77dd35cdb4af..8b4cea57a6c5c47f585f5fcae935771e575dcd18 100644 (file)
@@ -33,6 +33,9 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Daniel Martensson<daniel.martensson@stericsson.com>");
 MODULE_DESCRIPTION("CAIF SPI driver");
 
+/* Returns the number of padding bytes for alignment. */
+#define PAD_POW2(x, pow) ((((x)&((pow)-1))==0) ? 0 : (((pow)-((x)&((pow)-1)))))
+
 static int spi_loop;
 module_param(spi_loop, bool, S_IRUGO);
 MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode.");
@@ -41,7 +44,10 @@ MODULE_PARM_DESC(spi_loop, "SPI running in loopback mode.");
 module_param(spi_frm_align, int, S_IRUGO);
 MODULE_PARM_DESC(spi_frm_align, "SPI frame alignment.");
 
-/* SPI padding options. */
+/*
+ * SPI padding options.
+ * Warning: must be a base of 2 (& operation used) and can not be zero !
+ */
 module_param(spi_up_head_align, int, S_IRUGO);
 MODULE_PARM_DESC(spi_up_head_align, "SPI uplink head alignment.");
 
@@ -240,15 +246,13 @@ static ssize_t dbgfs_frame(struct file *file, char __user *user_buf,
 static const struct file_operations dbgfs_state_fops = {
        .open = dbgfs_open,
        .read = dbgfs_state,
-       .owner = THIS_MODULE,
-       .llseek = default_llseek,
+       .owner = THIS_MODULE
 };
 
 static const struct file_operations dbgfs_frame_fops = {
        .open = dbgfs_open,
        .read = dbgfs_frame,
-       .owner = THIS_MODULE,
-       .llseek = default_llseek,
+       .owner = THIS_MODULE
 };
 
 static inline void dev_debugfs_add(struct cfspi *cfspi)
@@ -337,6 +341,9 @@ int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
        u8 *dst = buf;
        caif_assert(buf);
 
+       if (cfspi->slave && !cfspi->slave_talked)
+               cfspi->slave_talked = true;
+
        do {
                struct sk_buff *skb;
                struct caif_payload_info *info;
@@ -357,8 +364,8 @@ int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
                 * Compute head offset i.e. number of bytes to add to
                 * get the start of the payload aligned.
                 */
-               if (spi_up_head_align) {
-                       spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+               if (spi_up_head_align > 1) {
+                       spad = 1 + PAD_POW2((info->hdr_len + 1), spi_up_head_align);
                        *dst = (u8)(spad - 1);
                        dst += spad;
                }
@@ -373,7 +380,7 @@ int cfspi_xmitfrm(struct cfspi *cfspi, u8 *buf, size_t len)
                 * Compute tail offset i.e. number of bytes to add to
                 * get the complete CAIF frame aligned.
                 */
-               epad = (skb->len + spad) & spi_up_tail_align;
+               epad = PAD_POW2((skb->len + spad), spi_up_tail_align);
                dst += epad;
 
                dev_kfree_skb(skb);
@@ -417,14 +424,14 @@ int cfspi_xmitlen(struct cfspi *cfspi)
                 * Compute head offset i.e. number of bytes to add to
                 * get the start of the payload aligned.
                 */
-               if (spi_up_head_align)
-                       spad = 1 + ((info->hdr_len + 1) & spi_up_head_align);
+               if (spi_up_head_align > 1)
+                       spad = 1 + PAD_POW2((info->hdr_len + 1), spi_up_head_align);
 
                /*
                 * Compute tail offset i.e. number of bytes to add to
                 * get the complete CAIF frame aligned.
                 */
-               epad = (skb->len + spad) & spi_up_tail_align;
+               epad = PAD_POW2((skb->len + spad), spi_up_tail_align);
 
                if ((skb->len + spad + epad + frm_len) <= CAIF_MAX_SPI_FRAME) {
                        skb_queue_tail(&cfspi->chead, skb);
@@ -433,6 +440,7 @@ int cfspi_xmitlen(struct cfspi *cfspi)
                } else {
                        /* Put back packet. */
                        skb_queue_head(&cfspi->qhead, skb);
+                       break;
                }
        } while (pkts <= CAIF_MAX_SPI_PKTS);
 
@@ -453,6 +461,15 @@ static void cfspi_ss_cb(bool assert, struct cfspi_ifc *ifc)
 {
        struct cfspi *cfspi = (struct cfspi *)ifc->priv;
 
+       /*
+        * The slave device is the master on the link. Interrupts before the
+        * slave has transmitted are considered spurious.
+        */
+       if (cfspi->slave && !cfspi->slave_talked) {
+               printk(KERN_WARNING "CFSPI: Spurious SS interrupt.\n");
+               return;
+       }
+
        if (!in_interrupt())
                spin_lock(&cfspi->lock);
        if (assert) {
@@ -465,7 +482,8 @@ static void cfspi_ss_cb(bool assert, struct cfspi_ifc *ifc)
                spin_unlock(&cfspi->lock);
 
        /* Wake up the xfer thread. */
-       wake_up_interruptible(&cfspi->wait);
+       if (assert)
+               wake_up_interruptible(&cfspi->wait);
 }
 
 static void cfspi_xfer_done_cb(struct cfspi_ifc *ifc)
@@ -523,7 +541,7 @@ int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
                 * Compute head offset i.e. number of bytes added to
                 * get the start of the payload aligned.
                 */
-               if (spi_down_head_align) {
+               if (spi_down_head_align > 1) {
                        spad = 1 + *src;
                        src += spad;
                }
@@ -564,7 +582,7 @@ int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len)
                 * Compute tail offset i.e. number of bytes added to
                 * get the complete CAIF frame aligned.
                 */
-               epad = (pkt_len + spad) & spi_down_tail_align;
+               epad = PAD_POW2((pkt_len + spad), spi_down_tail_align);
                src += epad;
        } while ((src - buf) < len);
 
@@ -625,11 +643,20 @@ int cfspi_spi_probe(struct platform_device *pdev)
        cfspi->ndev = ndev;
        cfspi->pdev = pdev;
 
-       /* Set flow info */
+       /* Set flow info. */
        cfspi->flow_off_sent = 0;
        cfspi->qd_low_mark = LOW_WATER_MARK;
        cfspi->qd_high_mark = HIGH_WATER_MARK;
 
+       /* Set slave info. */
+       if (!strncmp(cfspi_spi_driver.driver.name, "cfspi_sspi", 10)) {
+               cfspi->slave = true;
+               cfspi->slave_talked = false;
+       } else {
+               cfspi->slave = false;
+               cfspi->slave_talked = false;
+       }
+
        /* Assign the SPI device. */
        cfspi->dev = dev;
        /* Assign the device ifc to this SPI interface. */
index 2111dbfea6feb8b53f56e73567e54fd4d11a818b..1b9943a4edabb8f48678d7384ac2141d47264908 100644 (file)
@@ -36,10 +36,15 @@ static inline int forward_to_spi_cmd(struct cfspi *cfspi)
 #endif
 
 int spi_frm_align = 2;
-int spi_up_head_align = 1;
-int spi_up_tail_align;
-int spi_down_head_align = 3;
-int spi_down_tail_align = 1;
+
+/*
+ * SPI padding options.
+ * Warning: must be a base of 2 (& operation used) and can not be zero !
+ */
+int spi_up_head_align   = 1 << 1;
+int spi_up_tail_align   = 1 << 0;
+int spi_down_head_align = 1 << 2;
+int spi_down_tail_align = 1 << 1;
 
 #ifdef CONFIG_DEBUG_FS
 static inline void debugfs_store_prev(struct cfspi *cfspi)
index 407d4e2720750246356af4cf7fd627fe9cad3d91..046d846c652dc4c807bb79b9ee5ffe343368919d 100644 (file)
@@ -3341,7 +3341,6 @@ static int __devinit init_one(struct pci_dev *pdev,
                                adapter->name = adapter->port[i]->name;
 
                        __set_bit(i, &adapter->registered_device_map);
-                       netif_tx_stop_all_queues(adapter->port[i]);
                }
        }
        if (!adapter->registered_device_map) {
index f17703f410b3673a096aec05f9085329650c5c52..f50bc98310f8b319cf8cdfe1f1b63a23fff19e72 100644 (file)
@@ -3736,7 +3736,6 @@ static int __devinit init_one(struct pci_dev *pdev,
 
                        __set_bit(i, &adapter->registered_device_map);
                        adapter->chan_map[adap2pinfo(adapter, i)->tx_chan] = i;
-                       netif_tx_stop_all_queues(adapter->port[i]);
                }
        }
        if (!adapter->registered_device_map) {
index 555ecc5a2e939b25028ac6a61cf2792da379caa7..6de5e2e448a5671afcdbb441e3810531690ddfb0 100644 (file)
@@ -2600,7 +2600,6 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
                pi->xact_addr_filt = -1;
                pi->rx_offload = RX_CSO;
                netif_carrier_off(netdev);
-               netif_tx_stop_all_queues(netdev);
                netdev->irq = pdev->irq;
 
                netdev->features = (NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
index 385dc3204cb7eefbbaa184f0601267abe7c392ee..06bb9b7994585318bb723046a0804a39a4a4a5e8 100644 (file)
@@ -2871,7 +2871,6 @@ static int __devinit emac_probe(struct platform_device *ofdev,
        SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops);
 
        netif_carrier_off(ndev);
-       netif_stop_queue(ndev);
 
        err = register_netdev(ndev);
        if (err) {
index d85edf3119c2625d999b22a41b6159ba9ebf7a24..c57d9a43cecacbf8a668a0c4b1cca5e7b93c3521 100644 (file)
@@ -2955,11 +2955,7 @@ jme_init_one(struct pci_dev *pdev,
         * Tell stack that we are not ready to work until open()
         */
        netif_carrier_off(netdev);
-       netif_stop_queue(netdev);
 
-       /*
-        * Register netdev
-        */
        rc = register_netdev(netdev);
        if (rc) {
                pr_err("Cannot register net device\n");
index a75ba9517404d94ca7c3da59472cfb80a57025c6..e1d30d7f207121a5de4636fd85b8bf7d9b76acb5 100644 (file)
@@ -41,9 +41,6 @@
 MODULE_DESCRIPTION("QLogic/NetXen (1/10) GbE Converged Ethernet Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(NETXEN_NIC_LINUX_VERSIONID);
-MODULE_FIRMWARE(NX_P2_MN_ROMIMAGE_NAME);
-MODULE_FIRMWARE(NX_P3_CT_ROMIMAGE_NAME);
-MODULE_FIRMWARE(NX_P3_MN_ROMIMAGE_NAME);
 MODULE_FIRMWARE(NX_UNIFIED_ROMIMAGE_NAME);
 
 char netxen_nic_driver_name[] = "netxen_nic";
index 7a298cdf9ab398135b2f59df9c7ad642c8f8840b..a3dcd04be22f6291e2546f84e474cef31e7fae34 100644 (file)
@@ -1450,7 +1450,6 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
        netdev->irq = adapter->msix_entries[0].vector;
 
        netif_carrier_off(netdev);
-       netif_stop_queue(netdev);
 
        err = register_netdev(netdev);
        if (err) {
index 52f38e12a879db9d344fb80f169f05eba31fa860..50f712e99e9634d2a348ba497a146b3d86c9dfde 100644 (file)
@@ -22,7 +22,7 @@
 #define __SMSC911X_H__
 
 #define TX_FIFO_LOW_THRESHOLD  ((u32)1600)
-#define SMSC911X_EEPROM_SIZE   ((u32)7)
+#define SMSC911X_EEPROM_SIZE   ((u32)128)
 #define USE_DEBUG              0
 
 /* This is the maximum number of packets to be received every
index 28e1ffb13db99df5b0537a7426b2af3c03980feb..c78a50586c1d86a0fffa9a59ab461a1996da8122 100644 (file)
@@ -2021,7 +2021,6 @@ static int __devinit de_init_one (struct pci_dev *pdev,
        de->media_timer.data = (unsigned long) de;
 
        netif_carrier_off(dev);
-       netif_stop_queue(dev);
 
        /* wake up device, assign resources */
        rc = pci_enable_device(pdev);
index ca7fc9df1ccf900533d56c35326b360316283af2..c04d49e31f814fe11d2f1b730dcba014afeb324c 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/usb/usbnet.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
+#include <linux/pm_runtime.h>
 
 #define DRIVER_VERSION         "22-Aug-2005"
 
@@ -1273,6 +1274,16 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
        struct usb_device               *xdev;
        int                             status;
        const char                      *name;
+       struct usb_driver       *driver = to_usb_driver(udev->dev.driver);
+
+       /* usbnet already took usb runtime pm, so have to enable the feature
+        * for usb interface, otherwise usb_autopm_get_interface may return
+        * failure if USB_SUSPEND(RUNTIME_PM) is enabled.
+        */
+       if (!driver->supports_autosuspend) {
+               driver->supports_autosuspend = 1;
+               pm_runtime_enable(&udev->dev);
+       }
 
        name = udev->dev.driver->name;
        info = (struct driver_info *) prod->driver_info;
index 32dee2ce5d3177706f8bc7394794952a87389324..d5ef696298eed37db811f55e60c0b7f3c0ded6f6 100644 (file)
@@ -54,6 +54,7 @@
 
 #define DRV_DESCRIPTION "802.11 data/management/control stack"
 #define DRV_NAME        "libipw"
+#define DRV_PROCNAME   "ieee80211"
 #define DRV_VERSION    LIBIPW_VERSION
 #define DRV_COPYRIGHT   "Copyright (C) 2004-2005 Intel Corporation <jketreno@linux.intel.com>"
 
@@ -293,16 +294,16 @@ static int __init libipw_init(void)
        struct proc_dir_entry *e;
 
        libipw_debug_level = debug;
-       libipw_proc = proc_mkdir("ieee80211", init_net.proc_net);
+       libipw_proc = proc_mkdir(DRV_PROCNAME, init_net.proc_net);
        if (libipw_proc == NULL) {
-               LIBIPW_ERROR("Unable to create " DRV_NAME
+               LIBIPW_ERROR("Unable to create " DRV_PROCNAME
                                " proc directory\n");
                return -EIO;
        }
        e = proc_create("debug_level", S_IRUGO | S_IWUSR, libipw_proc,
                        &debug_level_proc_fops);
        if (!e) {
-               remove_proc_entry(DRV_NAME, init_net.proc_net);
+               remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
                libipw_proc = NULL;
                return -EIO;
        }
@@ -319,7 +320,7 @@ static void __exit libipw_exit(void)
 #ifdef CONFIG_LIBIPW_DEBUG
        if (libipw_proc) {
                remove_proc_entry("debug_level", libipw_proc);
-               remove_proc_entry(DRV_NAME, init_net.proc_net);
+               remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
                libipw_proc = NULL;
        }
 #endif                         /* CONFIG_LIBIPW_DEBUG */
index 359d1e04626cb938784290a5700058a3115d7b34..f0d63892264410b23e19753885868cca81071eda 100644 (file)
@@ -35,7 +35,7 @@
 
 #ifdef CONFIG_SH_SECUREEDGE5410
 #include <asm/rtc.h>
-#include <mach/snapgear.h>
+#include <mach/secureedge5410.h>
 
 #define        RTC_RESET       0x1000
 #define        RTC_IODATA      0x0800
index fd0d1b98901c2a0c13cc925e078139be079d1f43..09615b51d5910e6b1b899e265836cb3137440ad1 100644 (file)
@@ -90,8 +90,8 @@ struct clk_rate_round_data {
 static long clk_rate_round_helper(struct clk_rate_round_data *rounder)
 {
        unsigned long rate_error, rate_error_prev = ~0UL;
-       unsigned long rate_best_fit = rounder->rate;
        unsigned long highest, lowest, freq;
+       long rate_best_fit = -ENOENT;
        int i;
 
        highest = 0;
@@ -146,7 +146,7 @@ long clk_rate_table_round(struct clk *clk,
        };
 
        if (clk->nr_freqs < 1)
-               return 0;
+               return -ENOSYS;
 
        return clk_rate_round_helper(&table_round);
 }
@@ -541,6 +541,98 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
 }
 EXPORT_SYMBOL_GPL(clk_round_rate);
 
+long clk_round_parent(struct clk *clk, unsigned long target,
+                     unsigned long *best_freq, unsigned long *parent_freq,
+                     unsigned int div_min, unsigned int div_max)
+{
+       struct cpufreq_frequency_table *freq, *best = NULL;
+       unsigned long error = ULONG_MAX, freq_high, freq_low, div;
+       struct clk *parent = clk_get_parent(clk);
+
+       if (!parent) {
+               *parent_freq = 0;
+               *best_freq = clk_round_rate(clk, target);
+               return abs(target - *best_freq);
+       }
+
+       for (freq = parent->freq_table; freq->frequency != CPUFREQ_TABLE_END;
+            freq++) {
+               if (freq->frequency == CPUFREQ_ENTRY_INVALID)
+                       continue;
+
+               if (unlikely(freq->frequency / target <= div_min - 1)) {
+                       unsigned long freq_max;
+
+                       freq_max = (freq->frequency + div_min / 2) / div_min;
+                       if (error > target - freq_max) {
+                               error = target - freq_max;
+                               best = freq;
+                               if (best_freq)
+                                       *best_freq = freq_max;
+                       }
+
+                       pr_debug("too low freq %lu, error %lu\n", freq->frequency,
+                                target - freq_max);
+
+                       if (!error)
+                               break;
+
+                       continue;
+               }
+
+               if (unlikely(freq->frequency / target >= div_max)) {
+                       unsigned long freq_min;
+
+                       freq_min = (freq->frequency + div_max / 2) / div_max;
+                       if (error > freq_min - target) {
+                               error = freq_min - target;
+                               best = freq;
+                               if (best_freq)
+                                       *best_freq = freq_min;
+                       }
+
+                       pr_debug("too high freq %lu, error %lu\n", freq->frequency,
+                                freq_min - target);
+
+                       if (!error)
+                               break;
+
+                       continue;
+               }
+
+               div = freq->frequency / target;
+               freq_high = freq->frequency / div;
+               freq_low = freq->frequency / (div + 1);
+
+               if (freq_high - target < error) {
+                       error = freq_high - target;
+                       best = freq;
+                       if (best_freq)
+                               *best_freq = freq_high;
+               }
+
+               if (target - freq_low < error) {
+                       error = target - freq_low;
+                       best = freq;
+                       if (best_freq)
+                               *best_freq = freq_low;
+               }
+
+               pr_debug("%u / %lu = %lu, / %lu = %lu, best %lu, parent %u\n",
+                        freq->frequency, div, freq_high, div + 1, freq_low,
+                        *best_freq, best->frequency);
+
+               if (!error)
+                       break;
+       }
+
+       if (parent_freq)
+               *parent_freq = best->frequency;
+
+       return error;
+}
+EXPORT_SYMBOL_GPL(clk_round_parent);
+
 #ifdef CONFIG_PM
 static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state)
 {
index 873a99ff8f64a454a505d1838be751dad20ae181..e5e9e6735f7d62e3d585505de7be4fe379fbbd40 100644 (file)
@@ -79,7 +79,7 @@ static void __init intc_register_irq(struct intc_desc *desc,
         * Register the IRQ position with the global IRQ map, then insert
         * it in to the radix tree.
         */
-       irq_reserve_irqs(irq, 1);
+       irq_reserve_irq(irq);
 
        raw_spin_lock_irqsave(&intc_big_lock, flags);
        radix_tree_insert(&d->tree, enum_id, intc_irq_xlate_get(irq));
index 4187cce20ffdc9cd0997b276e2f5e8dc020e2519..a3677c9dfe36e3fa6ebcac37bee81af58d9ece5c 100644 (file)
@@ -60,5 +60,5 @@ void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs)
        int i;
 
        for (i = 0; i < nr_vecs; i++)
-               irq_reserve_irqs(evt2irq(vectors[i].vect), 1);
+               irq_reserve_irq(evt2irq(vectors[i].vect));
 }
index 5eafdf435550fb307d9423c602a50f78be0ca471..49aee27b296d06f488b116da35ea8703135adf96 100644 (file)
@@ -175,5 +175,9 @@ source "drivers/staging/intel_sst/Kconfig"
 
 source "drivers/staging/speakup/Kconfig"
 
+source "drivers/staging/cptm1217/Kconfig"
+
+source "drivers/staging/ste_rmi4/Kconfig"
+
 endif # !STAGING_EXCLUDE_BUILD
 endif # STAGING
index a97a955c094bc8aa0f8142917f2ece87ecb01eac..20c5641b6cd754686edb99cfb3941d3ad0785c38 100644 (file)
@@ -68,3 +68,5 @@ obj-$(CONFIG_BCM_WIMAX)       += bcm/
 obj-$(CONFIG_FT1000)           += ft1000/
 obj-$(CONFIG_SND_INTEL_SST)            += intel_sst/
 obj-$(CONFIG_SPEAKUP)  += speakup/
+obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217)      += cptm1217/
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4)   += ste_rmi4/
index 22c6c6659f5b5f9a004ed25ae4543e01c200380b..ee8b47746a155ece0fbc559803a40ecb71e6f21b 100644 (file)
@@ -285,9 +285,9 @@ A_STATUS SetupHIFScatterSupport(HIF_DEVICE *device, HIF_DEVICE_SCATTER_SUPPORT_I
     do {
         
             /* check if host supports scatter requests and it meets our requirements */
-        if (device->func->card->host->max_hw_segs < MAX_SCATTER_ENTRIES_PER_REQ) {
+        if (device->func->card->host->max_segs < MAX_SCATTER_ENTRIES_PER_REQ) {
             AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("HIF-SCATTER : host only supports scatter of : %d entries, need: %d \n",
-                    device->func->card->host->max_hw_segs, MAX_SCATTER_ENTRIES_PER_REQ));
+                    device->func->card->host->max_segs, MAX_SCATTER_ENTRIES_PER_REQ));
             status = A_ENOTSUP;
             break;    
         }
diff --git a/drivers/staging/ath6kl/os/linux/include/athendpack_linux.h b/drivers/staging/ath6kl/os/linux/include/athendpack_linux.h
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h b/drivers/staging/ath6kl/os/linux/include/athstartpack_linux.h
deleted file mode 100644 (file)
index e69de29..0000000
index 0587940d27238146a67ed765482877557f445206..6ea64200ad1669cc39d5a9f22e01ec9d7327bf4d 100644 (file)
@@ -149,7 +149,7 @@ void dec_module_count(void)
 
 int compare_orig(void *data1, void *data2)
 {
-       return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
+       return (compare_ether_addr(data1, data2) == 0 ? 1 : 0);
 }
 
 /* hashfunction to choose an entry in a hash table of given size */
@@ -192,16 +192,6 @@ int is_my_mac(uint8_t *addr)
 
 }
 
-int is_bcast(uint8_t *addr)
-{
-       return (addr[0] == (uint8_t)0xff) && (addr[1] == (uint8_t)0xff);
-}
-
-int is_mcast(uint8_t *addr)
-{
-       return *addr & 0x01;
-}
-
 module_init(batman_init);
 module_exit(batman_exit);
 
index 5e3f51681f5e7ac5e8356d9269f6f9ffbb346892..14d567d4911a961e4788245b5a9f0268baee2dab 100644 (file)
 #include <linux/mutex.h>       /* mutex */
 #include <linux/module.h>      /* needed by all modules */
 #include <linux/netdevice.h>   /* netdevice */
+#include <linux/etherdevice.h>
 #include <linux/if_ether.h>    /* ethernet header */
 #include <linux/poll.h>                /* poll_table */
 #include <linux/kthread.h>     /* kernel threads */
@@ -138,8 +139,6 @@ void dec_module_count(void);
 int compare_orig(void *data1, void *data2);
 int choose_orig(void *data, int32_t size);
 int is_my_mac(uint8_t *addr);
-int is_bcast(uint8_t *addr);
-int is_mcast(uint8_t *addr);
 
 #ifdef CONFIG_BATMAN_ADV_DEBUG
 int debug_log(struct bat_priv *bat_priv, char *fmt, ...);
index 90102631330b883ad1f3df3bc45f3494b7f06d91..d42c16559dff88a9cc7f2dd2b76a520e1c6852a5 100644 (file)
@@ -756,11 +756,11 @@ int recv_bat_packet(struct sk_buff *skb, struct batman_if *batman_if)
        ethhdr = (struct ethhdr *)skb_mac_header(skb);
 
        /* packet with broadcast indication but unicast recipient */
-       if (!is_bcast(ethhdr->h_dest))
+       if (!is_broadcast_ether_addr(ethhdr->h_dest))
                return NET_RX_DROP;
 
        /* packet with broadcast sender address */
-       if (is_bcast(ethhdr->h_source))
+       if (is_broadcast_ether_addr(ethhdr->h_source))
                return NET_RX_DROP;
 
        /* create a copy of the skb, if needed, to modify it. */
@@ -933,11 +933,11 @@ int recv_icmp_packet(struct sk_buff *skb, struct batman_if *recv_if)
        ethhdr = (struct ethhdr *)skb_mac_header(skb);
 
        /* packet with unicast indication but broadcast recipient */
-       if (is_bcast(ethhdr->h_dest))
+       if (is_broadcast_ether_addr(ethhdr->h_dest))
                return NET_RX_DROP;
 
        /* packet with broadcast sender address */
-       if (is_bcast(ethhdr->h_source))
+       if (is_broadcast_ether_addr(ethhdr->h_source))
                return NET_RX_DROP;
 
        /* not for me */
@@ -1107,11 +1107,11 @@ static int check_unicast_packet(struct sk_buff *skb, int hdr_size)
        ethhdr = (struct ethhdr *)skb_mac_header(skb);
 
        /* packet with unicast indication but broadcast recipient */
-       if (is_bcast(ethhdr->h_dest))
+       if (is_broadcast_ether_addr(ethhdr->h_dest))
                return -1;
 
        /* packet with broadcast sender address */
-       if (is_bcast(ethhdr->h_source))
+       if (is_broadcast_ether_addr(ethhdr->h_source))
                return -1;
 
        /* not for me */
@@ -1283,11 +1283,11 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if)
        ethhdr = (struct ethhdr *)skb_mac_header(skb);
 
        /* packet with broadcast indication but unicast recipient */
-       if (!is_bcast(ethhdr->h_dest))
+       if (!is_broadcast_ether_addr(ethhdr->h_dest))
                return NET_RX_DROP;
 
        /* packet with broadcast sender address */
-       if (is_bcast(ethhdr->h_source))
+       if (is_broadcast_ether_addr(ethhdr->h_source))
                return NET_RX_DROP;
 
        /* ignore broadcasts sent by myself */
index 3904db9ce7b1f00909ecf2f07df7b561da28ec56..820e14159dd3a40c287fc953b58036819c3e3b2e 100644 (file)
@@ -140,7 +140,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
        hna_local_add(soft_iface, ethhdr->h_source);
 
        /* ethernet packet should be broadcasted */
-       if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) {
+       if (is_multicast_ether_addr(ethhdr->h_dest)) {
                if (!bat_priv->primary_if)
                        goto dropped;
 
index 3d2c1bccf2e6a46ce28828a01c9cb0dc4a0a504f..395f1109d606d7089091005ab168062a8b84eb93 100644 (file)
@@ -135,9 +135,8 @@ static ssize_t vis_data_read_prim_sec(char *buff, struct hlist_head *if_list)
        hlist_for_each_entry(entry, pos, if_list, list) {
                if (entry->primary)
                        len += sprintf(buff + len, "PRIMARY, ");
-               else {
+               else
                        len += sprintf(buff + len,  "SEC %pM, ", entry->addr);
-               }
        }
 
        return len;
@@ -470,7 +469,7 @@ void receive_client_update_packet(struct bat_priv *bat_priv,
        int are_target = 0;
 
        /* clients shall not broadcast. */
-       if (is_bcast(vis_packet->target_orig))
+       if (is_broadcast_ether_addr(vis_packet->target_orig))
                return;
 
        /* Are we the target for this VIS packet? */
@@ -747,7 +746,7 @@ static void send_vis_packet(struct bat_priv *bat_priv, struct vis_info *info)
               ETH_ALEN);
        packet->ttl--;
 
-       if (is_bcast(packet->target_orig))
+       if (is_broadcast_ether_addr(packet->target_orig))
                broadcast_vis_packet(bat_priv, info);
        else
                unicast_vis_packet(bat_priv, info);
index 748460e898d8702b99309dc95a7c87117a2f7bbe..62f9135d4d40dd687e1f3401b6f1f3c2fbb46fc8 100644 (file)
@@ -7,53 +7,6 @@
 #define MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES 256
 #include "Debug.h"
 
-typedef struct _LIST_ENTRY{
-       struct _LIST_ENTRY      *next;
-       struct _LIST_ENTRY      *prev;
-} LIST_ENTRY, *PLIST_ENTRY;
-
-typedef struct _BCM_LIST_ENTRY {
-
-    LIST_ENTRY                 Link;
-
-} BCM_LIST_ENTRY, *PBCM_LIST_ENTRY;
-
-typedef enum _RCB_STATUS
-{
-       DRIVER_PROCESSED=1,
-       APPLICATION_PROCESSED
-} RCB_STATUS, *PRCB_STATUS;
-
-#define fFILLED 1
-#define fEMPTY 0
-
-struct _BCM_CB
-{
-       // The network packet that this RCB is receiving
-       PVOID                           pv_packet;
-       // Describes the length of the packet .
-       UINT                ui_packet_length;
-       // Pointer to the first buffer in the packet (only one buffer for Rx)
-       PUCHAR                          buffer;
-       atomic_t                status;
-       UINT                filled;
-} __attribute__((packed));
-typedef struct _BCM_CB BCM_CB,*PBCM_CB;
-
-typedef BCM_CB BCM_RCB, *PBCM_RCB;
-typedef BCM_CB BCM_TCB, *PBCM_TCB;
-
-/* This is to be stored in the "pvOsDepData" of ADAPTER */
-typedef struct LINUX_DEP_DATA
-{
-       struct net_device               *virtualdev;    /* Our Interface (veth0) */
-       struct net_device               *actualdev;     /* True Interface (eth0) */
-       struct net_device_stats netstats;       /* Net statistics */
-       struct fasync_struct    *async_queue;   /* For asynchronus notification */
-
-} LINUX_DEP_DATA, *PLINUX_DEP_DATA;
-
-
 struct _LEADER
 {
        USHORT  Vcid;
@@ -429,26 +382,28 @@ Driver adapter data structure
 struct _MINI_ADAPTER
 {
        struct _MINI_ADAPTER *next;
-       PVOID                       pvOsDepData;
+       struct net_device       *dev;
+       u32                     msg_enable;
+
        CHAR                *caDsxReqResp;
-       atomic_t                        ApplicationRunning;
+       atomic_t                ApplicationRunning;
        volatile INT            CtrlQueueLen;
-       atomic_t            AppCtrlQueueLen;
-       BOOLEAN             AppCtrlQueueOverFlow;
-       atomic_t                        CurrentApplicationCount;
-       atomic_t                        RegisteredApplicationCount;
-       BOOLEAN                     TimerActive;
-       ULONG                           StatisticsPointer;
+       atomic_t                AppCtrlQueueLen;
+       BOOLEAN                 AppCtrlQueueOverFlow;
+       atomic_t                CurrentApplicationCount;
+       atomic_t                RegisteredApplicationCount;
+       BOOLEAN                 LinkUpStatus;
+       BOOLEAN                 TimerActive;
+       u32                     StatisticsPointer;
        struct sk_buff          *RxControlHead;
        struct sk_buff          *RxControlTail;
-//     spinlock_t                      RxControlQueuelock;
+
        struct semaphore        RxAppControlQueuelock;
        struct semaphore        fw_download_sema;
 
        PPER_TARANG_DATA    pTarangs;
        spinlock_t                      control_queue_lock;
        wait_queue_head_t       process_read_wait_queue;
-       ULONG                   bcm_jiffies;    /* Store Jiffies value */
 
        // the pointer to the first packet we have queued in send
        // deserialized miniport support variables
@@ -458,24 +413,15 @@ struct _MINI_ADAPTER
        // this to keep track of the Tx and Rx MailBox Registers.
        atomic_t                    CurrNumFreeTxDesc;
        // to keep track the no of byte recieved
-       atomic_t                        RxRollOverCount;
        USHORT                          PrevNumRecvDescs;
        USHORT                          CurrNumRecvDescs;
-       atomic_t                        GoodRxByteCount;
-       atomic_t                        GoodRxPktCount;
-       atomic_t                        BadRxByteCount;
-       atomic_t                        RxPacketDroppedCount;
-       atomic_t                        GoodTxByteCount;
-       atomic_t                        TxTotalPacketCount;
-       atomic_t                        TxDroppedPacketCount;
-       ULONG                           LinkUpStatus;
-       BOOLEAN                     TransferMode;
        UINT                            u32TotalDSD;
        PacketInfo                  PackInfo[NO_OF_QUEUES];
        S_CLASSIFIER_RULE       astClassifierTable[MAX_CLASSIFIERS];
+       BOOLEAN                     TransferMode;
 
        /*************** qos ******************/
-       UINT                            bETHCSEnabled;
+       BOOLEAN                     bETHCSEnabled;
 
        ULONG                       BEBucketSize;
        ULONG                       rtPSBucketSize;
@@ -483,7 +429,6 @@ struct _MINI_ADAPTER
        BOOLEAN                     AutoLinkUp;
        BOOLEAN                     AutoSyncup;
 
-       struct net_device       *dev;
        int                             major;
        int                             minor;
        wait_queue_head_t       tx_packet_wait_queue;
@@ -491,8 +436,6 @@ struct _MINI_ADAPTER
        atomic_t                        process_waiting;
        BOOLEAN                         fw_download_done;
 
-       unsigned int            ctrlpkt_present;
-       BOOLEAN                         packets_given_to_all;
        char                            *txctlpacket[MAX_CNTRL_PKTS];
        atomic_t                        cntrlpktCnt ;
        atomic_t                        index_app_read_cntrlpkt;
@@ -502,34 +445,30 @@ struct _MINI_ADAPTER
        struct semaphore        rdmwrmsync;
 
        STTARGETDSXBUFFER       astTargetDsxBuffer[MAX_TARGET_DSX_BUFFERS];
-       ULONG                           ulFreeTargetBufferCnt;
+       ULONG                   ulFreeTargetBufferCnt;
        ULONG                   ulCurrentTargetBuffer;
        ULONG                   ulTotalTargetBuffersAvailable;
-       unsigned int            timeout;
-       int                             irq;
+
        unsigned long           chip_id;
-       unsigned int            bFlashBoot;
-       unsigned int            if_up;
-//     spinlock_t                      sleeper_lock;
-       atomic_t                        rdm_wrm_access;
-       atomic_t                        tx_rx_access;
+
        wait_queue_head_t       lowpower_mode_wait_queue;
-       atomic_t                        bAbortedByHost;
-       BOOLEAN                         bBinDownloaded;
-       BOOLEAN                         bCfgDownloaded;
-       USHORT                          usBestEffortQueueIndex;
-       BOOLEAN                         bSyncUpRequestSent;
-//     struct semaphore        data_packet_queue_lock;
+
+       BOOLEAN                 bFlashBoot;
+       BOOLEAN                 bBinDownloaded;
+       BOOLEAN                 bCfgDownloaded;
+       BOOLEAN                 bSyncUpRequestSent;
+       USHORT                  usBestEffortQueueIndex;
+
        wait_queue_head_t       ioctl_fw_dnld_wait_queue;
        BOOLEAN                         waiting_to_fw_download_done;
        pid_t                           fw_download_process_pid;
        PSTARGETPARAMS          pstargetparams;
        BOOLEAN                         device_removed;
        BOOLEAN                         DeviceAccess;
-       INT                                     DDRSetting;
+       BOOLEAN                         bIsAutoCorrectEnabled;
        BOOLEAN                         bDDRInitDone;
+       INT                             DDRSetting;
        ULONG                           ulPowerSaveMode;
-       BOOLEAN                         bIsAutoCorrectEnabled;
        spinlock_t                      txtransmitlock;
        B_UINT8                         txtransmit_running;
        /* Thread for control packet handling */
@@ -567,13 +506,13 @@ struct _MINI_ADAPTER
        unsigned int    usIdleModePattern;
        //BOOLEAN                       bTriedToWakeUpFromShutdown;
        BOOLEAN                 bLinkDownRequested;
-       unsigned int    check_for_hang;
+
        int                     downloadDDR;
        PHS_DEVICE_EXTENSION stBCMPhsContext;
        S_HDR_SUPRESSION_CONTEXTINFO    stPhsTxContextInfo;
        uint8_t                 ucaPHSPktRestoreBuf[2048];
        uint8_t                 bPHSEnabled;
-       int                     AutoFirmDld;
+       BOOLEAN                 AutoFirmDld;
        BOOLEAN         bMipsConfig;
        BOOLEAN         bDPLLConfig;
        UINT32                  aTxPktSizeHist[MIBS_MAX_HIST_ENTRIES];
@@ -599,10 +538,9 @@ struct _MINI_ADAPTER
 
 
        struct semaphore        NVMRdmWrmLock;
-       BOOLEAN                 bNetworkInterfaceRegistered;
-       BOOLEAN                 bNetdeviceNotifierRegistered;
+
        struct device *pstCreatedClassDevice;
-       BOOLEAN                 bUsbClassDriverRegistered;
+
 //     BOOLEAN                         InterfaceUpStatus;
        PFLASH2X_CS_INFO psFlash2xCSInfo;
        PFLASH_CS_INFO psFlashCSInfo ;
@@ -630,17 +568,13 @@ struct _MINI_ADAPTER
        struct semaphore        LowPowerModeSync;
        ULONG   liDrainCalculated;
        UINT gpioBitMap;
+
     S_BCM_DEBUG_STATE stDebugState;
 
 };
 typedef struct _MINI_ADAPTER MINI_ADAPTER, *PMINI_ADAPTER;
 
-
-typedef struct _DEVICE_EXTENSION
-{
-       PMINI_ADAPTER pAdapt;
-}DEVICE_EXTENSION,*PDEVICE_EXTENSION;
-
+#define GET_BCM_ADAPTER(net_dev)       netdev_priv(net_dev)
 
 struct _ETH_HEADER_STRUC {
     UCHAR       au8DestinationAddress[6];
diff --git a/drivers/staging/bcm/Arp.c b/drivers/staging/bcm/Arp.c
deleted file mode 100644 (file)
index d60d859..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-
-/*
- * File Name: Arp.c
- * Abstract: This file contains the routines for handling ARP PACKETS
- */
-#include "headers.h"
-#define        ARP_PKT_SIZE    60
-
-/* =========================================================================
- * Function    - reply_to_arp_request()
- *
- * Description - When this host tries to broadcast ARP request packet through
- *                              the virtual interface (veth0), reply directly to upper layer.
- *                              This function allocates a new skb for ARP reply packet,
- *                              fills in the fields of the packet and then sends it to
- *                              upper layer.
- *
- * Parameters  - skb:  Pointer to sk_buff structure of the ARP request pkt.
- *
- * Returns     - None
- * =========================================================================*/
-
-VOID
-reply_to_arp_request(struct sk_buff *skb)
-{
-       PMINI_ADAPTER           Adapter;
-       struct ArpHeader        *pArpHdr = NULL;
-       struct ethhdr           *pethhdr = NULL;
-       UCHAR                           uiIPHdr[4];
-       /* Check for valid skb */
-       if(skb == NULL)
-       {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Invalid skb: Cannot reply to ARP request\n");
-               return;
-       }
-
-
-       Adapter = GET_BCM_ADAPTER(skb->dev);
-       /* Print the ARP Request Packet */
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, ARP_RESP, DBG_LVL_ALL, "ARP Packet Dump :");
-       BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_TX, ARP_RESP, DBG_LVL_ALL, (PUCHAR)(skb->data), skb->len);
-
-       /*
-        * Extract the Ethernet Header and Arp Payload including Header
-     */
-       pethhdr = (struct ethhdr *)skb->data;
-       pArpHdr  = (struct ArpHeader *)(skb->data+ETH_HLEN);
-
-       if(Adapter->bETHCSEnabled)
-       {
-               if(memcmp(pethhdr->h_source, Adapter->dev->dev_addr, ETH_ALEN))
-               {
-                       bcm_kfree_skb(skb);
-                       return;
-               }
-       }
-
-       // Set the Ethernet Header First.
-       memcpy(pethhdr->h_dest, pethhdr->h_source, ETH_ALEN);
-       if(!memcmp(pethhdr->h_source, Adapter->dev->dev_addr, ETH_ALEN))
-       {
-               pethhdr->h_source[5]++;
-       }
-
-       /* Set the reply to ARP Reply */
-       pArpHdr->arp.ar_op = ntohs(ARPOP_REPLY);
-
-       /* Set the HW Address properly */
-       memcpy(pArpHdr->ar_sha, pethhdr->h_source, ETH_ALEN);
-       memcpy(pArpHdr->ar_tha, pethhdr->h_dest, ETH_ALEN);
-
-       // Swapping the IP Adddress
-       memcpy(uiIPHdr,pArpHdr->ar_sip,4);
-       memcpy(pArpHdr->ar_sip,pArpHdr->ar_tip,4);
-       memcpy(pArpHdr->ar_tip,uiIPHdr,4);
-
-       /* Print the ARP Reply Packet */
-
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, ARP_RESP, DBG_LVL_ALL, "ARP REPLY PACKET: ");
-
-       /* Send the Packet to upper layer */
-       BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_TX, ARP_RESP, DBG_LVL_ALL, (PUCHAR)(skb->data), skb->len);
-
-       skb->protocol = eth_type_trans(skb,skb->dev);
-       skb->pkt_type = PACKET_HOST;
-
-//     skb->mac.raw=skb->data+LEADER_SIZE;
-       skb_set_mac_header (skb, LEADER_SIZE);
-       netif_rx(skb);
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, ARP_RESP, DBG_LVL_ALL, "<=============\n");
-       return;
-}
-
-
index 77fdfe24d9990df393df9cc85b5ac95f27feb61f..8089d19e6c1b5ff493c74ba0efe2548043d9d95b 100644 (file)
@@ -12,7 +12,7 @@
 *
 * Returns        - Zero(Success)
 ****************************************************************/
-static struct class *bcm_class = NULL;
+
 static int bcm_char_open(struct inode *inode, struct file * filp)
 {
        PMINI_ADAPTER           Adapter = NULL;
@@ -93,7 +93,7 @@ static int bcm_char_release(struct inode *inode, struct file *filp)
     /*Stop Queuing the control response Packets*/
     atomic_dec(&Adapter->ApplicationRunning);
 
-    bcm_kfree(pTarang);
+    kfree(pTarang);
 
        /* remove this filp from the asynchronously notified filp's */
     filp->private_data = NULL;
@@ -102,11 +102,11 @@ static int bcm_char_release(struct inode *inode, struct file *filp)
 
 static ssize_t bcm_char_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos)
 {
-    PPER_TARANG_DATA pTarang = (PPER_TARANG_DATA)filp->private_data;
+       PPER_TARANG_DATA pTarang = filp->private_data;
        PMINI_ADAPTER   Adapter = pTarang->Adapter;
-    struct sk_buff* Packet = NULL;
-    UINT            PktLen = 0;
-       int                     wait_ret_val=0;
+       struct sk_buff* Packet = NULL;
+       ssize_t         PktLen = 0;
+       int             wait_ret_val=0;
 
        wait_ret_val = wait_event_interruptible(Adapter->process_read_wait_queue,
                (pTarang->RxAppControlHead || Adapter->device_removed));
@@ -139,14 +139,16 @@ static ssize_t bcm_char_read(struct file *filp, char __user *buf, size_t size, l
        if(Packet)
        {
                PktLen = Packet->len;
-               if(copy_to_user(buf, Packet->data, PktLen))
+               if(copy_to_user(buf, Packet->data, min_t(size_t, PktLen, size)))
                {
-                       bcm_kfree_skb(Packet);
+                       dev_kfree_skb(Packet);
                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "\nReturning from copy to user failure \n");
                        return -EFAULT;
                }
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Read %d Bytes From Adapter packet = 0x%p by process %d!\n", PktLen, Packet, current->pid);
-               bcm_kfree_skb(Packet);
+               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,
+                               "Read %zd Bytes From Adapter packet = %p by process %d!\n",
+                               PktLen, Packet, current->pid);
+               dev_kfree_skb(Packet);
        }
 
     BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "<====\n");
@@ -155,15 +157,12 @@ static ssize_t bcm_char_read(struct file *filp, char __user *buf, size_t size, l
 
 static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
 {
-    PPER_TARANG_DATA  pTarang = (PPER_TARANG_DATA)filp->private_data;
-       void __user *argp = (void __user *)argp;
+       PPER_TARANG_DATA  pTarang = filp->private_data;
+       void __user *argp = (void __user *)arg;
        PMINI_ADAPTER   Adapter = pTarang->Adapter;
        INT                     Status = STATUS_FAILURE;
-       IOCTL_BUFFER    IoBuffer={};
-#ifndef BCM_SHM_INTERFACE
-    int timeout = 0;
-#endif
-
+       int timeout = 0;
+       IOCTL_BUFFER    IoBuffer;
 
        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Parameters Passed to control IOCTL cmd=0x%X arg=0x%lX", cmd, arg);
 
@@ -204,50 +203,41 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
 
        Status = vendorextnIoctl(Adapter, cmd, arg);
        if(Status != CONTINUE_COMMON_PATH )
-       {
                 return Status;
-       }
 
        switch(cmd){
                // Rdms for Swin Idle...
                case IOCTL_BCM_REGISTER_READ_PRIVATE:
                {
                        RDM_BUFFER  sRdmBuffer = {0};
-                       PCHAR temp_buff = NULL;
-                       UINT Bufflen = 0;
+                       PCHAR temp_buff;
+                       UINT Bufflen;
+
                        /* Copy Ioctl Buffer structure */
-                       if(copy_from_user((PCHAR)&IoBuffer, argp,
-                               sizeof(IOCTL_BUFFER)))
-                       {
-                               Status = -EFAULT;
-                               break;
-                       }
+                       if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+                               return -EFAULT;
+
+                       if (IoBuffer.InputLength > sizeof(sRdmBuffer))
+                               return -EINVAL;
 
+                       if(copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
+                               return -EFAULT;
+
+                       /* FIXME: need to restrict BuffLen */
                        Bufflen = IoBuffer.OutputLength + (4 - IoBuffer.OutputLength%4)%4;
-                       temp_buff = (PCHAR)kmalloc(Bufflen, GFP_KERNEL);
+                       temp_buff = kmalloc(Bufflen, GFP_KERNEL);
                        if(!temp_buff)
-                       {
-                               return STATUS_FAILURE;
-                       }
-                       if(copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer,
-                               IoBuffer.InputLength))
-                       {
-                               Status = -EFAULT;
-                               break;
-                       }
+                               return -ENOMEM;
+
                        Status = rdmalt(Adapter, (UINT)sRdmBuffer.Register,
                                        (PUINT)temp_buff, Bufflen);
-                       if(Status != STATUS_SUCCESS)
-                       {
-                               bcm_kfree(temp_buff);
-                               return Status;
-                       }
-                       if(copy_to_user(IoBuffer.OutputBuffer,
-                               (PCHAR)temp_buff, (UINT)IoBuffer.OutputLength))
+                       if(Status == STATUS_SUCCESS)
                        {
-                               Status = -EFAULT;
+                               if(copy_to_user(IoBuffer.OutputBuffer, temp_buff, IoBuffer.OutputLength))
+                                       Status = -EFAULT;
                        }
-                       bcm_kfree(temp_buff);
+
+                       kfree(temp_buff);
                        break;
                }
                case IOCTL_BCM_REGISTER_WRITE_PRIVATE:
@@ -256,19 +246,16 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                        UINT uiTempVar=0;
                        /* Copy Ioctl Buffer structure */
 
-                       if(copy_from_user(&IoBuffer, argp,
-                               sizeof(IOCTL_BUFFER)))
-                       {
-                               Status = -EFAULT;
-                               break;
-                       }
+                       if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+                               return -EFAULT;
+
+                       if (IoBuffer.InputLength > sizeof(sWrmBuffer))
+                               return -EINVAL;
+
                        /* Get WrmBuffer structure */
-                       if(copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer,
-                               IoBuffer.InputLength))
-                       {
-                               Status = -EFAULT;
-                               break;
-                       }
+                       if(copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
+                               return -EFAULT;
+
                        uiTempVar = sWrmBuffer.Register & EEPROM_REJECT_MASK;
                        if(!((Adapter->pstargetparams->m_u32Customize) & VSG_MODE) &&
                                ((uiTempVar == EEPROM_REJECT_REG_1)||
@@ -277,8 +264,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                (uiTempVar == EEPROM_REJECT_REG_4)))
                        {
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "EEPROM Access Denied, not in VSG Mode\n");
-                               Status = -EFAULT;
-                               break;
+                               return -EFAULT;
                        }
                        Status = wrmalt(Adapter, (UINT)sWrmBuffer.Register,
                                                (PUINT)sWrmBuffer.Data, sizeof(ULONG));
@@ -305,56 +291,39 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                (Adapter->bPreparingForLowPowerMode ==TRUE))
                        {
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Device in Idle Mode, Blocking Rdms\n");
-                               Status = -EACCES;
-                               break;
+                               return -EACCES;
                        }
                        /* Copy Ioctl Buffer structure */
-                       if(copy_from_user(&IoBuffer, argp,
-                               sizeof(IOCTL_BUFFER)))
-                       {
-                               Status = -EFAULT;
-                               break;
-                       }
+                       if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+                               return -EFAULT;
+
+                       if (IoBuffer.InputLength > sizeof(sRdmBuffer))
+                               return -EINVAL;
 
-                       temp_buff = (PCHAR)kmalloc(IoBuffer.OutputLength, GFP_KERNEL);
+                       if(copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
+                               return -EFAULT;
+
+                       /* FIXME: don't trust user supplied length */
+                       temp_buff = kmalloc(IoBuffer.OutputLength, GFP_KERNEL);
                        if(!temp_buff)
-                       {
                                return STATUS_FAILURE;
-                       }
-                       if(copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer,
-                               IoBuffer.InputLength))
-                       {
-                               Status = -EFAULT;
-                               break;
-                       }
 
-                       if(
-#if !defined(BCM_SHM_INTERFACE)
-                               (((ULONG)sRdmBuffer.Register & 0x0F000000) != 0x0F000000) ||
-#endif
-                                       ((ULONG)sRdmBuffer.Register & 0x3)
-                         )
+                       if((((ULONG)sRdmBuffer.Register & 0x0F000000) != 0x0F000000) ||
+                          ((ULONG)sRdmBuffer.Register & 0x3))
                        {
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "RDM Done On invalid Address : %x Access Denied.\n",
                                        (int)sRdmBuffer.Register);
-                               Status = -EINVAL;
-                               break;
+                               return -EINVAL;
                        }
 
                        uiTempVar = sRdmBuffer.Register & EEPROM_REJECT_MASK;
                        Status = rdmaltWithLock(Adapter, (UINT)sRdmBuffer.Register,
                                                (PUINT)temp_buff, IoBuffer.OutputLength);
-                       if(Status != STATUS_SUCCESS)
-                       {
-                               bcm_kfree(temp_buff);
-                               return Status;
-                       }
-                       if(copy_to_user(IoBuffer.OutputBuffer,
-                               (PCHAR)temp_buff, (UINT)IoBuffer.OutputLength))
-                       {
-                               Status = -EFAULT;
-                       }
-                       bcm_kfree(temp_buff);
+                       if(Status == STATUS_SUCCESS)
+                               if(copy_to_user(IoBuffer.OutputBuffer, temp_buff, IoBuffer.OutputLength))
+                                       Status = -EFAULT;
+
+                       kfree(temp_buff);
                        break;
                }
                case IOCTL_BCM_REGISTER_WRITE:
@@ -367,36 +336,28 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                (Adapter->bPreparingForLowPowerMode ==TRUE))
                        {
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Device in Idle Mode, Blocking Wrms\n");
-                               Status = -EACCES;
-                               break;
+                               return -EACCES;
                        }
+
                        /* Copy Ioctl Buffer structure */
-                       if(copy_from_user((PCHAR)&IoBuffer, argp,
-                                       sizeof(IOCTL_BUFFER)))
-                       {
-                               Status = -EFAULT;
-                               break;
-                       }
+                       if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+                               return -EFAULT;
+
+                       if (IoBuffer.InputLength > sizeof(sWrmBuffer))
+                               return -EINVAL;
+
                        /* Get WrmBuffer structure */
-                       if(copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer,
-                               IoBuffer.InputLength))
-                       {
-                               Status = -EFAULT;
-                               break;
-                       }
-                       if(
-#if !defined(BCM_SHM_INTERFACE)
+                       if(copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
+                               return -EFAULT;
 
-                               (((ULONG)sWrmBuffer.Register & 0x0F000000) != 0x0F000000) ||
-#endif
-                                       ((ULONG)sWrmBuffer.Register & 0x3)
-                        )
+                       if( (((ULONG)sWrmBuffer.Register & 0x0F000000) != 0x0F000000) ||
+                                       ((ULONG)sWrmBuffer.Register & 0x3) )
                        {
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "WRM Done On invalid Address : %x Access Denied.\n",
                                                (int)sWrmBuffer.Register);
-                               Status = -EINVAL;
-                               break;
+                               return -EINVAL;
                        }
+
                        uiTempVar = sWrmBuffer.Register & EEPROM_REJECT_MASK;
                        if(!((Adapter->pstargetparams->m_u32Customize) & VSG_MODE) &&
                                ((uiTempVar == EEPROM_REJECT_REG_1)||
@@ -406,8 +367,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                (cmd == IOCTL_BCM_REGISTER_WRITE))
                        {
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "EEPROM Access Denied, not in VSG Mode\n");
-                               Status = -EFAULT;
-                               break;
+                               return -EFAULT;
                        }
 
                        Status = wrmaltWithLock(Adapter, (UINT)sWrmBuffer.Register,
@@ -436,19 +396,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                (Adapter->bPreparingForLowPowerMode ==TRUE))
                        {
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"GPIO Can't be set/clear in Low power Mode");
-                               Status = -EACCES;
-                               break;
+                               return -EACCES;
                        }
                        if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
-                       {
-                               Status = -EFAULT;
-                               break;
-                   }
+                               return -EFAULT;
+                       if (IoBuffer.InputLength > sizeof(gpio_info))
+                               return -EINVAL;
                        if(copy_from_user(&gpio_info, IoBuffer.InputBuffer, IoBuffer.InputLength))
-                       {
-                               Status = -EFAULT;
-                               break;
-                       }
+                               return -EFAULT;
                        uiBit  = gpio_info.uiGpioNumber;
                        uiOperation = gpio_info.uiGpioValue;
 
@@ -517,8 +472,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                break;
                case BCM_LED_THREAD_STATE_CHANGE_REQ:
                {
-
-                       USER_THREAD_REQ threadReq = {0};
+                       USER_THREAD_REQ threadReq = { 0 };
                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"User made LED thread InActive");
 
                        if((Adapter->IdleMode == TRUE) ||
@@ -529,21 +483,16 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                Status = -EACCES;
                                break;
                        }
-                       Status =copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER));
-                       if(Status)
-                       {
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying the IOBufer from user space err:%d",Status);
-                               Status = -EFAULT;
-                               break;
-                       }
 
-                       Status= copy_from_user(&threadReq, IoBuffer.InputBuffer, IoBuffer.InputLength);
-                       if(Status)
-                       {
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying the InputBuffer from user space err:%d",Status);
-                               Status = -EFAULT;
-                               break;
-                       }
+                       if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+                               return -EFAULT;
+
+                       if (IoBuffer.InputLength > sizeof(threadReq))
+                               return -EINVAL;
+
+                       if (copy_from_user(&threadReq, IoBuffer.InputBuffer, IoBuffer.InputLength))
+                               return -EFAULT;
+
                        //if LED thread is running(Actively or Inactively) set it state to make inactive
                        if(Adapter->LEDInfo.led_thread_running)
                        {
@@ -572,19 +521,13 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                        if((Adapter->IdleMode == TRUE) ||
                                (Adapter->bShutStatus ==TRUE) ||
                                (Adapter->bPreparingForLowPowerMode ==TRUE))
-                       {
-                               Status = -EACCES;
-                               break;
-                       }
-                       if(copy_from_user((PCHAR)&IoBuffer, argp, sizeof(IOCTL_BUFFER))) {
-                               Status = -EFAULT;
-                               break;
-                       }
-                if(copy_from_user(&gpio_info, IoBuffer.InputBuffer, IoBuffer.InputLength))
-                {
-                    Status = -EFAULT;
-                    break;
-                }
+                               return -EACCES;
+                       if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+                               return -EFAULT;
+                       if (IoBuffer.InputLength > sizeof(gpio_info))
+                               return -EINVAL;
+                       if(copy_from_user(&gpio_info, IoBuffer.InputBuffer, IoBuffer.InputLength))
+                               return -EFAULT;
                 uiBit  = gpio_info.uiGpioNumber;
                                  //Set the gpio output register
                                Status = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER,
@@ -608,25 +551,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                if((Adapter->IdleMode == TRUE) ||
                                (Adapter->bShutStatus ==TRUE) ||
                                (Adapter->bPreparingForLowPowerMode ==TRUE))
-                               {
-                                       Status = -EINVAL;
-                                       break;
-                               }
-                               Status = copy_from_user( (PCHAR)&IoBuffer, argp, sizeof( IOCTL_BUFFER));
-                               if(Status)
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying the IOBufer from user space err:%d",Status);
-                                       Status = -EFAULT;
-                                       break;
-                               }
+                                       return -EINVAL;
+                               if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+                                       return -EFAULT;
+                               if (IoBuffer.InputLength > sizeof(gpio_multi_info))
+                                       return -EINVAL;
+                               if (copy_from_user(&gpio_multi_info, IoBuffer.InputBuffer, IoBuffer.InputLength))
+                                       return -EFAULT;
 
-                               Status = copy_from_user( &gpio_multi_info, IoBuffer.InputBuffer, IoBuffer.InputLength);
-                               if(Status)
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying the IOBufer Contents from user space err:%d",Status);
-                                       Status = -EFAULT;
-                                       break;
-                               }
                                if(IsReqGpioIsLedInNVM(Adapter,pgpio_multi_info[WIMAX_IDX].uiGPIOMask)== FALSE)
                                {
                                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Sorry, Requested GPIO<0x%X> is not correspond to NVM LED bit map<0x%X>!!!",pgpio_multi_info[WIMAX_IDX].uiGPIOMask,Adapter->gpioBitMap);
@@ -686,7 +618,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                if(Status)
                                {
                                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying Content to IOBufer for user space err:%d",Status);
-                                       Status = -EFAULT;
                                        break;
                                }
                        }
@@ -700,25 +631,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                        if((Adapter->IdleMode == TRUE) ||
                                (Adapter->bShutStatus ==TRUE) ||
                                (Adapter->bPreparingForLowPowerMode ==TRUE))
-                       {
-                                       Status = -EINVAL;
-                                       break;
-                       }
-                       Status = copy_from_user(&IoBuffer, argp, sizeof( IOCTL_BUFFER));
-                       if(Status)
-                       {
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying the IOBufer from user space err:%d",Status);
-                               Status = -EFAULT;
-                               break;
-                       }
+                                       return -EINVAL;
 
-                       Status = copy_from_user( &gpio_multi_mode, IoBuffer.InputBuffer, IoBuffer.InputLength);
-                       if(Status)
-                       {
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying the IOBufer Contents from user space err:%d",Status);
-                               Status = -EFAULT;
-                               break;
-                       }
+                       if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+                               return -EFAULT;
+                       if (IoBuffer.InputLength > sizeof(gpio_multi_mode))
+                               return -EINVAL;
+                       if (copy_from_user(&gpio_multi_mode, IoBuffer.InputBuffer, IoBuffer.InputLength))
+                               return -EFAULT;
 
                        Status = rdmaltWithLock( Adapter, ( UINT) GPIO_MODE_REGISTER, ( PUINT) ucResetValue, sizeof( UINT));
                        if( STATUS_SUCCESS != Status)
@@ -769,7 +689,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                        if(Status)
                        {
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Failed while copying Content to IOBufer for user space err:%d",Status);
-                               Status = -EFAULT;
                                break;
                        }
                }
@@ -783,24 +702,20 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                case IOCTL_IDLE_REQ:
                {
                        PVOID pvBuffer=NULL;
+
                        /* Copy Ioctl Buffer structure */
-                       if(copy_from_user(&IoBuffer, argp,
-                                                       sizeof(IOCTL_BUFFER)))
-                       {
-                               Status = -EFAULT;
-                               break;
-                       }
-                       pvBuffer=kmalloc(IoBuffer.InputLength, GFP_KERNEL);
+                       if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+                               return -EFAULT;
+
+                       /* FIXME: don't accept any length from user */
+                       pvBuffer = kmalloc(IoBuffer.InputLength, GFP_KERNEL);
                        if(!pvBuffer)
-                       {
                                return -ENOMEM;
-                       }
 
-                       if(copy_from_user(pvBuffer, IoBuffer.InputBuffer,
-                                       IoBuffer.InputLength))
+                       if(copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
                        {
                                Status = -EFAULT;
-                               bcm_kfree(pvBuffer);
+                               kfree(pvBuffer);
                                break;
                        }
 
@@ -820,10 +735,9 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                        Status = CopyBufferToControlPacket(Adapter, (PVOID)pvBuffer);
                cntrlEnd:
                        up(&Adapter->LowPowerModeSync);
-                       bcm_kfree(pvBuffer);
+                       kfree(pvBuffer);
                        break;
                }
-#ifndef BCM_SHM_INTERFACE
                case IOCTL_BCM_BUFFER_DOWNLOAD_START:
                {
                        INT NVMAccess = down_trylock(&Adapter->NVMRdmWrmLock) ;
@@ -844,7 +758,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                Status = reset_card_proc(Adapter);
                                if(Status)
                                {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "reset_card_proc Failed!\n");
+                                       pr_err(PFX "%s: reset_card_proc Failed!\n", Adapter->dev->name);
                                        up(&Adapter->fw_download_sema);
                                        up(&Adapter->NVMRdmWrmLock);
                                        break;
@@ -862,7 +776,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                }
                case IOCTL_BCM_BUFFER_DOWNLOAD:
                        {
-                               FIRMWARE_INFO   *psFwInfo=NULL;
+                               FIRMWARE_INFO   *psFwInfo = NULL;
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Starting the firmware download PID =0x%x!!!!\n", current->pid);
                        do{
                                if(!down_trylock(&Adapter->fw_download_sema))
@@ -871,29 +785,23 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                        Status=-EINVAL;
                                        break;
                                }
+
                                /* Copy Ioctl Buffer structure */
                                if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "copy_from_user 1 failed\n");
-                                       Status = -EFAULT;
-                                       break;
-                               }
+                                       return -EFAULT;
+
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Length for FW DLD is : %lx\n",
                                                                                IoBuffer.InputLength);
-                               psFwInfo=kmalloc(sizeof(*psFwInfo), GFP_KERNEL);
+
+                               if (IoBuffer.InputLength > sizeof(FIRMWARE_INFO))
+                                       return -EINVAL;
+
+                               psFwInfo = kmalloc(sizeof(*psFwInfo), GFP_KERNEL);
                                if(!psFwInfo)
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Failed to allocate buffer!!!!\n");
-                                       Status = -ENOMEM;
-                                       break;
-                               }
-                               if(copy_from_user(psFwInfo, IoBuffer.InputBuffer,
-                                                       IoBuffer.InputLength))
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy_from_user 2 failed\n");
-                                       Status = -EFAULT;
-                                       break;
-                               }
+                                       return -ENOMEM;
+
+                               if(copy_from_user(psFwInfo, IoBuffer.InputBuffer, IoBuffer.InputLength))
+                                       return -EFAULT;
 
                                if(!psFwInfo->pvMappedFirmwareAddress ||
                                                (psFwInfo->u32FirmwareLength == 0))
@@ -929,7 +837,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                          if(Status != STATUS_SUCCESS)
                                        up(&Adapter->fw_download_sema);
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, OSAL_DBG, DBG_LVL_ALL, "IOCTL: Firmware File Uploaded\n");
-                               bcm_kfree(psFwInfo);
+                               kfree(psFwInfo);
                                break;
                        }
                case IOCTL_BCM_BUFFER_DOWNLOAD_STOP:
@@ -946,7 +854,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                Adapter->bBinDownloaded=TRUE;
                                Adapter->bCfgDownloaded=TRUE;
                                atomic_set(&Adapter->CurrNumFreeTxDesc, 0);
-                               atomic_set(&Adapter->RxRollOverCount, 0);
+
                                Adapter->CurrNumRecvDescs=0;
                                Adapter->downloadDDR = 0;
 
@@ -999,7 +907,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                        up(&Adapter->NVMRdmWrmLock);
                        break;
                }
-#endif
                case IOCTL_BE_BUCKET_SIZE:
                        Adapter->BEBucketSize = *(PULONG)arg;
                        Status = STATUS_SUCCESS;
@@ -1044,22 +951,16 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                        break;
 
                case IOCTL_GET_PACK_INFO:
-                       if(copy_to_user(argp, &Adapter->PackInfo,
-                               sizeof(PacketInfo)*NO_OF_QUEUES))
-                       {
-                               Status = -EFAULT;
-                               break;
-                       }
+                       if(copy_to_user(argp, &Adapter->PackInfo, sizeof(PacketInfo)*NO_OF_QUEUES))
+                               return -EFAULT;
                        Status = STATUS_SUCCESS;
                        break;
                case IOCTL_BCM_SWITCH_TRANSFER_MODE:
                {
                        UINT uiData = 0;
                        if(copy_from_user(&uiData, argp, sizeof(UINT)))
-                       {
-                               Status = -EFAULT;
-                               break;
-                       }
+                               return -EFAULT;
+
                        if(uiData)      /* Allow All Packets */
                        {
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_SWITCH_TRANSFER_MODE: ETH_PACKET_TUNNELING_MODE\n");
@@ -1078,22 +979,17 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                {
                        /* Copy Ioctl Buffer structure */
                        if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
-                       {
-                               Status = -EFAULT;
-                               break;
-                       }
-                       if(copy_to_user(IoBuffer.OutputBuffer,
-                               VER_FILEVERSION_STR, (UINT)IoBuffer.OutputLength))
-                       {
-                               Status = -EFAULT;
-                               break;
-                       }
+                               return -EFAULT;
+
+                       if(copy_to_user(IoBuffer.OutputBuffer, VER_FILEVERSION_STR, IoBuffer.OutputLength))
+                               return -EFAULT;
                        Status = STATUS_SUCCESS;
                        break;
                }
                case IOCTL_BCM_GET_CURRENT_STATUS:
                {
-                       LINK_STATE *plink_state = NULL;
+                       LINK_STATE link_state;
+
                        /* Copy Ioctl Buffer structure */
                        if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
                        {
@@ -1101,12 +997,15 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                Status = -EFAULT;
                                break;
                        }
-                       plink_state = (LINK_STATE*)arg;
-                       plink_state->bIdleMode = (UCHAR)Adapter->IdleMode;
-                       plink_state->bShutdownMode = Adapter->bShutStatus;
-                       plink_state->ucLinkStatus = (UCHAR)Adapter->LinkStatus;
-                       if(copy_to_user(IoBuffer.OutputBuffer,
-                               (PUCHAR)plink_state, (UINT)IoBuffer.OutputLength))
+
+
+                       memset(&link_state, 0, sizeof(link_state));
+                       link_state.bIdleMode = Adapter->IdleMode;
+                       link_state.bShutdownMode = Adapter->bShutStatus;
+                       link_state.ucLinkStatus = Adapter->LinkStatus;
+
+                       if (copy_to_user(IoBuffer.OutputBuffer, &link_state,
+                                        min_t(size_t, sizeof(link_state), IoBuffer.OutputLength)))
                        {
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy_to_user Failed..\n");
                                Status = -EFAULT;
@@ -1118,17 +1017,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
         case IOCTL_BCM_SET_MAC_TRACING:
         {
             UINT  tracing_flag;
+
             /* copy ioctl Buffer structure */
-                       if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
-                       {
-                               Status = -EFAULT;
-                               break;
-                       }
-                       if(copy_from_user(&tracing_flag, IoBuffer.InputBuffer,sizeof(UINT)))
-            {
-                               Status = -EFAULT;
-                               break;
-                       }
+           if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+                   return -EFAULT;
+
+           if(copy_from_user(&tracing_flag,IoBuffer.InputBuffer,sizeof(UINT)))
+                   return -EFAULT;
+
             if (tracing_flag)
                 Adapter->pTarangs->MacTracingEnabled = TRUE;
             else
@@ -1138,72 +1034,53 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                case IOCTL_BCM_GET_DSX_INDICATION:
                {
                        ULONG ulSFId=0;
-                       if(copy_from_user((PCHAR)&IoBuffer, argp,
-                                       sizeof(IOCTL_BUFFER)))
-                       {
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Invalid IO buffer!!!" );
-                               Status = -EFAULT;
-                               break;
-                       }
+                       if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+                               return -EFAULT;
+
                        if(IoBuffer.OutputLength < sizeof(stLocalSFAddIndicationAlt))
                        {
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Mismatch req: %lx needed is =0x%zx!!!",
-                                       IoBuffer.OutputLength, sizeof(stLocalSFAddIndicationAlt));
+                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,
+                                               "Mismatch req: %lx needed is =0x%zx!!!",
+                                               IoBuffer.OutputLength, sizeof(stLocalSFAddIndicationAlt));
                                return -EINVAL;
                        }
-                       if(copy_from_user(&ulSFId, IoBuffer.InputBuffer,
-                                       sizeof(ulSFId)))
-                       {
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Invalid SFID!!! %lu", ulSFId );
-                               Status = -EFAULT;
-                               break;
-                       }
+
+                       if(copy_from_user(&ulSFId, IoBuffer.InputBuffer, sizeof(ulSFId)))
+                               return -EFAULT;
+
                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Get DSX Data SF ID is =%lx\n", ulSFId );
-                       get_dsx_sf_data_to_application(Adapter, ulSFId,
-                               IoBuffer.OutputBuffer);
+                       get_dsx_sf_data_to_application(Adapter, ulSFId, IoBuffer.OutputBuffer);
                        Status=STATUS_SUCCESS;
                }
                break;
                case IOCTL_BCM_GET_HOST_MIBS:
                {
-                       PCHAR temp_buff;
+                       PVOID temp_buff;
 
                        if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
-                       {
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy_from user for IoBuff failed\n");
-                               Status = -EFAULT;
-                               break;
-                       }
+                               return -EFAULT;
 
                        if(IoBuffer.OutputLength != sizeof(S_MIBS_HOST_STATS_MIBS))
                        {
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Length Check failed %lu %zd\n", IoBuffer.OutputLength,
-                                                                                       sizeof(S_MIBS_HOST_STATS_MIBS));
-                       return -EINVAL;
+                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,
+                                               "Length Check failed %lu %zd\n",
+                                               IoBuffer.OutputLength, sizeof(S_MIBS_HOST_STATS_MIBS));
+                               return -EINVAL;
                        }
 
-                       temp_buff = (PCHAR)kmalloc(IoBuffer.OutputLength, GFP_KERNEL);
-
+                       /* FIXME: HOST_STATS are too big for kmalloc (122048)! */
+                       temp_buff = kzalloc(sizeof(S_MIBS_HOST_STATS_MIBS), GFP_KERNEL);
                        if(!temp_buff)
-                       {
                                return STATUS_FAILURE;
-                       }
-
-                       Status = ProcessGetHostMibs(Adapter,
-                                       (PUCHAR)temp_buff, IoBuffer.OutputLength);
 
-               Status = GetDroppedAppCntrlPktMibs((PVOID)temp_buff,
-                                                                       (PPER_TARANG_DATA)filp->private_data);
+                       Status = ProcessGetHostMibs(Adapter, temp_buff);
+                       GetDroppedAppCntrlPktMibs(temp_buff, pTarang);
 
-                       if(copy_to_user(IoBuffer.OutputBuffer,(PCHAR)temp_buff,
-                               sizeof(S_MIBS_HOST_STATS_MIBS)))
-                       {
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy to user failed\n");
-                               bcm_kfree(temp_buff);
-                               return -EFAULT;
-                       }
+                       if (Status != STATUS_FAILURE)
+                               if(copy_to_user(IoBuffer.OutputBuffer, temp_buff, sizeof(S_MIBS_HOST_STATS_MIBS)))
+                                       Status = -EFAULT;
 
-                       bcm_kfree(temp_buff);
+                       kfree(temp_buff);
                        break;
                }
 
@@ -1213,10 +1090,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                Adapter->usIdleModePattern = ABORT_IDLE_MODE;
                                Adapter->bWakeUpDevice = TRUE;
                                wake_up(&Adapter->process_rx_cntrlpkt);
-                               #if 0
-                               Adapter->bTriedToWakeUpFromlowPowerMode = TRUE;
-                               InterfaceAbortIdlemode (Adapter, Adapter->usIdleModePattern);
-                               #endif
                        }
                        Status = STATUS_SUCCESS;
                        break;
@@ -1235,24 +1108,20 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                        Status = -EACCES;
                                        break;
                                }
+
                                /* Copy Ioctl Buffer structure */
-                               if(copy_from_user((PCHAR)&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
-                               {
-                                       Status = -EFAULT;
-                                       break;
-                               }
+                               if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+                                       return -EFAULT;
 
-                               pvBuffer=kmalloc(IoBuffer.InputLength, GFP_KERNEL);
+                               /* FIXME: restrict length */
+                               pvBuffer = kmalloc(IoBuffer.InputLength, GFP_KERNEL);
                                if(!pvBuffer)
-                               {
                                        return -ENOMEM;
-                                       break;
-                               }
 
                                /* Get WrmBuffer structure */
-                if(copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
+                               if(copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength))
                                {
-                                       bcm_kfree(pvBuffer);
+                                       kfree(pvBuffer);
                                        Status = -EFAULT;
                                        break;
                                }
@@ -1262,7 +1131,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                if(((ULONG)pBulkBuffer->Register & 0x0F000000) != 0x0F000000 ||
                                        ((ULONG)pBulkBuffer->Register & 0x3))
                                {
-                                       bcm_kfree(pvBuffer);
+                                       kfree(pvBuffer);
                     BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0,"WRM Done On invalid Address : %x Access Denied.\n",(int)pBulkBuffer->Register);
                                        Status = -EINVAL;
                                        break;
@@ -1277,7 +1146,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                        (uiTempVar == EEPROM_REJECT_REG_4)) &&
                                        (cmd == IOCTL_BCM_REGISTER_WRITE))
                                {
-                                       bcm_kfree(pvBuffer);
+                                       kfree(pvBuffer);
                     BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0,"EEPROM Access Denied, not in VSG Mode\n");
                                        Status = -EFAULT;
                                        break;
@@ -1293,30 +1162,19 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "WRM Failed\n");
                                }
 
-                               bcm_kfree(pvBuffer);
+                               kfree(pvBuffer);
                                break;
                        }
 
                case IOCTL_BCM_GET_NVM_SIZE:
-                       {
-
                        if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
-                       {
-                               //IOLog("failed NVM first");
-                               Status = -EFAULT;
-                               break;
-                       }
+                               return -EFAULT;
+
                        if(Adapter->eNVMType == NVM_EEPROM || Adapter->eNVMType == NVM_FLASH ) {
-                               if(copy_to_user(IoBuffer.OutputBuffer,
-                                       (unsigned char *)&Adapter->uiNVMDSDSize, (UINT)sizeof(UINT)))
-                               {
-                                               Status = -EFAULT;
-                                               return Status;
-                               }
+                               if(copy_to_user(IoBuffer.OutputBuffer, &Adapter->uiNVMDSDSize, sizeof(UINT)))
+                                       return -EFAULT;
                        }
-
                        Status = STATUS_SUCCESS ;
-                       }
                        break;
 
                case IOCTL_BCM_CAL_INIT :
@@ -1325,38 +1183,26 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                UINT uiSectorSize = 0 ;
                                if(Adapter->eNVMType == NVM_FLASH)
                                {
-                                       Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER));
-                                       if(Status)
-                                       {
-                                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Copy From User space failed. status :%d", Status);
+                                       if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
                                                return -EFAULT;
-                                       }
-                                       uiSectorSize = *((PUINT)(IoBuffer.InputBuffer)); /* FIXME: unchecked __user access */
+
+                                       if (copy_from_user(&uiSectorSize, IoBuffer.InputBuffer, sizeof(UINT)))
+                                               return -EFAULT;
+
                                        if((uiSectorSize < MIN_SECTOR_SIZE) || (uiSectorSize > MAX_SECTOR_SIZE))
                                        {
-
-                                               Status = copy_to_user(IoBuffer.OutputBuffer,
-                                                                       (unsigned char *)&Adapter->uiSectorSize ,
-                                                                       (UINT)sizeof(UINT));
-                                               if(Status)
-                                               {
-                                                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Coping the sector size to use space failed. status:%d",Status);
-                                                               return -EFAULT;
-                                               }
+                                               if (copy_to_user(IoBuffer.OutputBuffer, &Adapter->uiSectorSize,
+                                                                sizeof(UINT)))
+                                                       return -EFAULT;
                                        }
                                        else
                                        {
                                                if(IsFlash2x(Adapter))
                                                {
-                                                       Status = copy_to_user(IoBuffer.OutputBuffer,
-                                                                       (unsigned char *)&Adapter->uiSectorSize ,
-                                                                       (UINT)sizeof(UINT));
-                                                       if(Status)
-                                                       {
-                                                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Coping the sector size to use space failed. status:%d",Status);
-                                                                       return -EFAULT;
-                                                       }
-
+                                                       if (copy_to_user(IoBuffer.OutputBuffer,
+                                                                        &Adapter->uiSectorSize ,
+                                                                        sizeof(UINT)))
+                                                           return -EFAULT;
                                                }
                                                else
                                                {
@@ -1380,25 +1226,19 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                        }
                        break;
         case IOCTL_BCM_SET_DEBUG :
+#ifdef DEBUG
             {
                 USER_BCM_DBG_STATE sUserDebugState;
 
 //                             BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "Entered the ioctl %x \n", IOCTL_BCM_SET_DEBUG );
 
                                BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "In SET_DEBUG ioctl\n");
-                               Status = copy_from_user((PCHAR)&IoBuffer, argp, sizeof(IOCTL_BUFFER));
-                               if(Status)
-                               {
-                                       BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "Copy from user failed\n");
-                                       Status = -EFAULT;
-                                       break;
-                               }
-                               Status = copy_from_user(&sUserDebugState,IoBuffer.InputBuffer, sizeof(USER_BCM_DBG_STATE));
-                               if(Status)
-                               {
-                                       BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0,  "Copy of IoBuffer.InputBuffer failed");
+                               if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
                                        return -EFAULT;
-                               }
+
+                               if (copy_from_user(&sUserDebugState, IoBuffer.InputBuffer, sizeof(USER_BCM_DBG_STATE)))
+                                       return -EFAULT;
+
 
                                BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "IOCTL_BCM_SET_DEBUG: OnOff=%d Type = 0x%x ",
                                sUserDebugState.OnOff, sUserDebugState.Type);
@@ -1421,15 +1261,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                 BCM_SHOW_DEBUG_BITMAP(Adapter);
 
                        }
+#endif
                        break;
                case IOCTL_BCM_NVM_READ:
                case IOCTL_BCM_NVM_WRITE:
                        {
-
-                               NVM_READWRITE  stNVMReadWrite = {};
+                               NVM_READWRITE  stNVMReadWrite;
                                PUCHAR pReadData = NULL;
-                               void __user * pBuffertobeCopied = NULL;
-                               ULONG ulDSDMagicNumInUsrBuff = 0 ;
+                               ULONG ulDSDMagicNumInUsrBuff = 0;
                                struct timeval tv0, tv1;
                                memset(&tv0,0,sizeof(struct timeval));
                                memset(&tv1,0,sizeof(struct timeval));
@@ -1454,21 +1293,12 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                        /* Copy Ioctl Buffer structure */
 
                                if(copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"copy_from_user failed\n");
-                                       Status = -EFAULT;
-                                       break;
-                               }
-                               if(IOCTL_BCM_NVM_READ == cmd)
-                                       pBuffertobeCopied = IoBuffer.OutputBuffer;
-                               else
-                                       pBuffertobeCopied = IoBuffer.InputBuffer;
+                                       return -EFAULT;
 
-                               if(copy_from_user(&stNVMReadWrite, pBuffertobeCopied,sizeof(NVM_READWRITE)))
-                               {
-                                       Status = -EFAULT;
-                                       break;
-                               }
+                               if(copy_from_user(&stNVMReadWrite,
+                                                 (IOCTL_BCM_NVM_READ == cmd) ? IoBuffer.OutputBuffer : IoBuffer.InputBuffer,
+                                                 sizeof(NVM_READWRITE)))
+                                       return -EFAULT;
 
                                //
                                // Deny the access if the offset crosses the cal area limit.
@@ -1481,18 +1311,15 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                        break;
                                }
 
-                               pReadData =(PCHAR)kmalloc(stNVMReadWrite.uiNumBytes, GFP_KERNEL);
-
+                               pReadData = kzalloc(stNVMReadWrite.uiNumBytes, GFP_KERNEL);
                                if(!pReadData)
                                        return -ENOMEM;
 
-                               memset(pReadData,0,stNVMReadWrite.uiNumBytes);
-
                                if(copy_from_user(pReadData, stNVMReadWrite.pBuffer,
                                                        stNVMReadWrite.uiNumBytes))
                                {
                                        Status = -EFAULT;
-                                       bcm_kfree(pReadData);
+                                       kfree(pReadData);
                                        break;
                                }
 
@@ -1507,7 +1334,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                        {
                                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Device is in Idle/Shutdown Mode\n");
                                                up(&Adapter->NVMRdmWrmLock);
-                                               bcm_kfree(pReadData);
+                                               kfree(pReadData);
                                                return -EACCES;
                                        }
 
@@ -1518,13 +1345,12 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
 
                                        if(Status != STATUS_SUCCESS)
                                                {
-                                                       bcm_kfree(pReadData);
+                                                       kfree(pReadData);
                                                        return Status;
                                                }
-                                       if(copy_to_user(stNVMReadWrite.pBuffer,
-                                                       pReadData, (UINT)stNVMReadWrite.uiNumBytes))
+                                       if(copy_to_user(stNVMReadWrite.pBuffer,pReadData, stNVMReadWrite.uiNumBytes))
                                                {
-                                                       bcm_kfree(pReadData);
+                                                       kfree(pReadData);
                                                        Status = -EFAULT;
                                                }
                                }
@@ -1539,7 +1365,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                        {
                                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Device is in Idle/Shutdown Mode\n");
                                                up(&Adapter->NVMRdmWrmLock);
-                                               bcm_kfree(pReadData);
+                                               kfree(pReadData);
                                                return -EACCES;
                                        }
 
@@ -1567,7 +1393,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                                        {
                                                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"DSD Sig is present neither in Flash nor User provided Input..");
                                                                up(&Adapter->NVMRdmWrmLock);
-                                                               bcm_kfree(pReadData);
+                                                               kfree(pReadData);
                                                                return Status;
                                                        }
 
@@ -1576,7 +1402,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                                        {
                                                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"DSD Sig is present neither in Flash nor User provided Input..");
                                                                up(&Adapter->NVMRdmWrmLock);
-                                                               bcm_kfree(pReadData);
+                                                               kfree(pReadData);
                                                                return Status;
                                                        }
                                                }
@@ -1593,7 +1419,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
 
                                        if(Status != STATUS_SUCCESS)
                                        {
-                                               bcm_kfree(pReadData);
+                                               kfree(pReadData);
                                                return Status;
                                        }
                                }
@@ -1601,7 +1427,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, " timetaken by Write/read :%ld msec\n",(tv1.tv_sec - tv0.tv_sec)*1000 +(tv1.tv_usec - tv0.tv_usec)/1000);
 
 
-                               bcm_kfree(pReadData);
+                               kfree(pReadData);
                                Status = STATUS_SUCCESS;
                        }
                        break;
@@ -1614,7 +1440,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                UINT BuffSize = 0;
                                UINT ReadBytes = 0;
                                UINT ReadOffset = 0;
-                               char __user *OutPutBuff = NULL;
+                               void __user *OutPutBuff;
 
                                if(IsFlash2x(Adapter) != TRUE)
                                {
@@ -1623,20 +1449,12 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                }
 
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_FLASH2X_SECTION_READ Called");
-                               Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER));
-                               if(Status)
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
+                               if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
                                        return -EFAULT;
-                               }
 
                                //Reading FLASH 2.x READ structure
-                               Status = copy_from_user(&sFlash2xRead, IoBuffer.InputBuffer,sizeof(FLASH2X_READWRITE));
-                               if(Status)
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of Input Buffer failed");
+                               if (copy_from_user(&sFlash2xRead, IoBuffer.InputBuffer,sizeof(FLASH2X_READWRITE)))
                                        return -EFAULT;
-                               }
 
 
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"\nsFlash2xRead.Section :%x" ,sFlash2xRead.Section);
@@ -1672,7 +1490,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                {
                                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Device is in Idle/Shutdown Mode\n");
                                        up(&Adapter->NVMRdmWrmLock);
-                                       bcm_kfree(pReadBuff);
+                                       kfree(pReadBuff);
                                        return -EACCES;
                                }
 
@@ -1700,7 +1518,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                        if(Status)
                                        {
                                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Copy to use failed with status :%d", Status);
-                                               Status = -EFAULT;
                                                break;
                                        }
                                        NOB = NOB - ReadBytes;
@@ -1712,15 +1529,15 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
 
                                }
                                up(&Adapter->NVMRdmWrmLock);
-                               bcm_kfree(pReadBuff);
+                               kfree(pReadBuff);
 
                         }
                         break ;
                case IOCTL_BCM_FLASH2X_SECTION_WRITE :
                         {
                                FLASH2X_READWRITE sFlash2xWrite = {0};
-                               PUCHAR pWriteBuff = NULL;
-                               void __user *InputAddr = NULL;
+                               PUCHAR pWriteBuff;
+                               void __user *InputAddr;
                                UINT NOB = 0;
                                UINT BuffSize = 0;
                                UINT WriteOffset = 0;
@@ -1737,33 +1554,17 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
 
 
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, " IOCTL_BCM_FLASH2X_SECTION_WRITE Called");
-                               Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER));
-                               if(Status)
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
+                               if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
                                        return -EFAULT;
-                               }
 
                                //Reading FLASH 2.x READ structure
-                               Status = copy_from_user(&sFlash2xWrite, IoBuffer.InputBuffer, sizeof(FLASH2X_READWRITE));
-                               if(Status)
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Reading of output Buffer from IOCTL buffer fails");
+                               if (copy_from_user(&sFlash2xWrite, IoBuffer.InputBuffer, sizeof(FLASH2X_READWRITE)))
                                        return -EFAULT;
-                               }
 
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"\nsFlash2xRead.Section :%x" ,sFlash2xWrite.Section);
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"\nsFlash2xRead.offset :%d" ,sFlash2xWrite.offset);
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"\nsFlash2xRead.numOfBytes :%x" ,sFlash2xWrite.numOfBytes);
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"\nsFlash2xRead.bVerify :%x\n" ,sFlash2xWrite.bVerify);
-                               #if 0
-                               if((sFlash2xWrite.Section == ISO_IMAGE1) ||(sFlash2xWrite.Section == ISO_IMAGE2) ||
-                                       (sFlash2xWrite.Section == DSD0) || (sFlash2xWrite.Section == DSD1) || (sFlash2xWrite.Section == DSD2))
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"ISO/DSD Image write is not allowed....  ");
-                                       return STATUS_FAILURE ;
-                               }
-                               #endif
                                if((sFlash2xWrite.Section != VSA0) && (sFlash2xWrite.Section != VSA1) &&
                                        (sFlash2xWrite.Section != VSA2) )
                                {
@@ -1783,12 +1584,10 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                else
                                        BuffSize = NOB ;
 
-                               pWriteBuff = (PCHAR)kmalloc(BuffSize, GFP_KERNEL);
+                               pWriteBuff = kmalloc(BuffSize, GFP_KERNEL);
                                if(pWriteBuff == NULL)
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Memory allocation failed for Flash 2.x Read Structure");
                                        return -ENOMEM;
-                               }
+
 
                                //extracting the remainder of the given offset.
                                WriteBytes = Adapter->uiSectorSize ;
@@ -1805,7 +1604,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                {
                                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Device is in Idle/Shutdown Mode\n");
                                        up(&Adapter->NVMRdmWrmLock);
-                                       bcm_kfree(pWriteBuff);
+                                       kfree(pWriteBuff);
                                        return -EACCES;
                                }
 
@@ -1816,7 +1615,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                        if(Status)
                                        {
                                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Copy to user failed with status :%d", Status);
-                                               Status = -EFAULT;
                                                break ;
                                        }
                                        BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,pWriteBuff,WriteBytes);
@@ -1844,28 +1642,22 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                }       while(NOB > 0);
                                BcmFlash2xWriteSig(Adapter,sFlash2xWrite.Section);
                                up(&Adapter->NVMRdmWrmLock);
-                               bcm_kfree(pWriteBuff);
+                               kfree(pWriteBuff);
                         }
                         break ;
                case IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP :
                         {
 
-                               PFLASH2X_BITMAP psFlash2xBitMap = NULL ;
+                                PFLASH2X_BITMAP psFlash2xBitMap;
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP Called");
 
-                               Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER));
-                               if(Status)
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
+                               if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
                                        return -EFAULT;
-                               }
+
                                if(IoBuffer.OutputLength != sizeof(FLASH2X_BITMAP))
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Structure size mismatch Lib :0x%lx Driver :0x%zx ",IoBuffer.OutputLength, sizeof(FLASH2X_BITMAP));
-                                       break;
-                               }
+                                       return -EINVAL;
 
-                               psFlash2xBitMap = (PFLASH2X_BITMAP)kzalloc(sizeof(FLASH2X_BITMAP), GFP_KERNEL);
+                               psFlash2xBitMap = kzalloc(sizeof(FLASH2X_BITMAP), GFP_KERNEL);
                                if(psFlash2xBitMap == NULL)
                                {
                                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Memory is not available");
@@ -1880,20 +1672,16 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                {
                                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Device is in Idle/Shutdown Mode\n");
                                        up(&Adapter->NVMRdmWrmLock);
-                                       bcm_kfree(psFlash2xBitMap);
+                                       kfree(psFlash2xBitMap);
                                        return -EACCES;
                                }
 
                                BcmGetFlash2xSectionalBitMap(Adapter, psFlash2xBitMap);
                                up(&Adapter->NVMRdmWrmLock);
-                               Status = copy_to_user(IoBuffer.OutputBuffer, psFlash2xBitMap, sizeof(FLASH2X_BITMAP));
-                               if(Status)
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "copying Flash2x bitMap failed");
-                                       bcm_kfree(psFlash2xBitMap);
-                                       return -EFAULT;
-                               }
-                               bcm_kfree(psFlash2xBitMap);
+                               if (copy_to_user(IoBuffer.OutputBuffer, psFlash2xBitMap, sizeof(FLASH2X_BITMAP)))
+                                       Status = -EFAULT;
+
+                               kfree(psFlash2xBitMap);
                         }
                         break ;
                case IOCTL_BCM_SET_ACTIVE_SECTION :
@@ -1911,14 +1699,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                if(Status)
                                {
                                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
-                                       return -EFAULT;
+                                       return Status;
                                }
 
                                Status = copy_from_user(&eFlash2xSectionVal,IoBuffer.InputBuffer, sizeof(INT));
                                if(Status)
                                {
                                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of flash section val failed");
-                                       return -EFAULT;
+                                       return Status;
                                }
 
                                down(&Adapter->NVMRdmWrmLock);
@@ -1946,29 +1734,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                Adapter->bAllDSDWriteAllow = FALSE ;
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"IOCTL_BCM_IDENTIFY_ACTIVE_SECTION called");
 
-                               #if 0
-                               SECTION_TYPE section = 0 ;
-
-
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "IOCTL_BCM_IDENTIFY_ACTIVE_SECTION Called");
-                               Status = copy_from_user((PCHAR)&IoBuffer, (PCHAR)arg, sizeof(IOCTL_BUFFER));
-                               if(Status)
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Copy of IOCTL BUFFER failed");
-                                       return -EFAULT;
-                               }
-                               Status = copy_from_user((PCHAR)section,(PCHAR)&IoBuffer, sizeof(INT));
-                               if(Status)
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Copy of section type failed failed");
-                                       return -EFAULT;
-                               }
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Read Section :%d", section);
-                               if(section == DSD)
-                                       Adapter->ulFlashCalStart = Adapter->uiActiveDSDOffsetAtFwDld ;
-                               else
-                                       Status = STATUS_FAILURE ;
-                               #endif
                                Status = STATUS_SUCCESS ;
                         }
                         break ;
@@ -1989,14 +1754,14 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                if(Status)
                                {
                                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed Status :%d", Status);
-                                       return -EFAULT;
+                                       return Status;
                                }
 
-                               Status = copy_from_user(&sCopySectStrut,IoBuffer.InputBuffer, sizeof(FLASH2X_COPY_SECTION));
+                               Status = copy_from_user(&sCopySectStrut, IoBuffer.InputBuffer, sizeof(FLASH2X_COPY_SECTION));
                                if(Status)
                                {
                                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of Copy_Section_Struct failed with Status :%d", Status);
-                                       return -EFAULT;
+                                       return Status;
                                }
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Source SEction :%x", sCopySectStrut.SrcSection);
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "Destination SEction :%x", sCopySectStrut.DstSection);
@@ -2067,7 +1832,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                if(Status)
                                {
                                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
-                                       Status = -EFAULT;
                                        break;
                                }
                                if(Adapter->eNVMType != NVM_FLASH)
@@ -2080,35 +1844,18 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                {
 
                                        if(IoBuffer.OutputLength < sizeof(FLASH2X_CS_INFO))
-                                       {
-                                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0," Passed buffer size:0x%lX is insufficient for the CS structure.. \nRequired size :0x%zx ",IoBuffer.OutputLength, sizeof(FLASH2X_CS_INFO));
-                                               Status = -EINVAL;
-                                               break;
-                                       }
+                                               return -EINVAL;
 
-                                       Status = copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlash2xCSInfo, sizeof(FLASH2X_CS_INFO));
-                                       if(Status)
-                                       {
-                                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "copying Flash2x cs info failed");
-                                               Status = -EFAULT;
-                                               break;
-                                       }
+                                       if (copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlash2xCSInfo, sizeof(FLASH2X_CS_INFO)))
+                                               return -EFAULT;
                                }
                                else
                                {
                                        if(IoBuffer.OutputLength < sizeof(FLASH_CS_INFO))
-                                       {
-                                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0," Passed buffer size:0x%lX is insufficient for the CS structure.. Required size :0x%zx ",IoBuffer.OutputLength, sizeof(FLASH_CS_INFO));
-                                               Status = -EINVAL;
-                                               break;
-                                       }
-                                       Status = copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlashCSInfo, sizeof(FLASH_CS_INFO));
-                                       if(Status)
-                                       {
-                                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "copying Flash CS info failed");
-                                               Status = -EFAULT;
-                                               break;
-                                       }
+                                               return -EINVAL;
+
+                                       if (copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlashCSInfo, sizeof(FLASH_CS_INFO)))
+                                               return -EFAULT;
 
                                 }
                          }
@@ -2130,13 +1877,13 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                if(Status)
                                {
                                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
-                                       return -EFAULT;
+                                       return Status;
                                }
-                               Status = copy_from_user(&eFlash2xSectionVal,IoBuffer.InputBuffer, sizeof(INT));
+                               Status = copy_from_user(&eFlash2xSectionVal, IoBuffer.InputBuffer, sizeof(INT));
                                if(Status)
                                {
                                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of flash section val failed");
-                                       return -EFAULT;
+                                       return Status;
                                }
 
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Read Section :%d", eFlash2xSectionVal);
@@ -2166,13 +1913,13 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                case IOCTL_BCM_NVM_RAW_READ :
                         {
 
-                               NVM_READWRITE  stNVMRead = {};
+                                NVM_READWRITE stNVMRead;
                                INT NOB ;
                                INT BuffSize ;
                                INT ReadOffset = 0;
                                UINT ReadBytes = 0 ;
-                               PUCHAR pReadBuff = NULL ;
-                               char __user *OutPutBuff = NULL ;
+                               PUCHAR pReadBuff;
+                               void __user *OutPutBuff;
 
                                if(Adapter->eNVMType != NVM_FLASH)
                                {
@@ -2189,10 +1936,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                }
 
                                if(copy_from_user(&stNVMRead, IoBuffer.OutputBuffer,sizeof(NVM_READWRITE)))
-                               {
-                                       Status = -EFAULT;
-                                       break;
-                               }
+                                       return -EFAULT;
 
                                NOB = stNVMRead.uiNumBytes;
                                //In Raw-Read max Buff size : 64MB
@@ -2202,11 +1946,10 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                else
                                        BuffSize = NOB ;
 
-                               ReadOffset = stNVMRead.uiOffset ;
+                               ReadOffset = stNVMRead.uiOffset;
                                OutPutBuff = stNVMRead.pBuffer;
 
-
-                               pReadBuff = (PCHAR)kzalloc(BuffSize , GFP_KERNEL);
+                               pReadBuff = kzalloc(BuffSize , GFP_KERNEL);
                                if(pReadBuff == NULL)
                                {
                                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Memory allocation failed for Flash 2.x Read Structure");
@@ -2220,7 +1963,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                        (Adapter->bPreparingForLowPowerMode ==TRUE))
                                {
                                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"Device is in Idle/Shutdown Mode\n");
-                                       bcm_kfree(pReadBuff);
+                                       kfree(pReadBuff);
                                        up(&Adapter->NVMRdmWrmLock);
                                        return -EACCES;
                                }
@@ -2241,13 +1984,12 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                                break;
                                        }
 
-                                       BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,pReadBuff, ReadBytes);
+                                       BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,pReadBuff,ReadBytes);
 
                                        Status = copy_to_user(OutPutBuff, pReadBuff,ReadBytes);
                                        if(Status)
                                        {
                                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Copy to use failed with status :%d", Status);
-                                               Status = -EFAULT;
                                                break;
                                        }
                                        NOB = NOB - ReadBytes;
@@ -2260,7 +2002,7 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                }
                                Adapter->bFlashRawRead = FALSE ;
                                up(&Adapter->NVMRdmWrmLock);
-                               bcm_kfree(pReadBuff);
+                               kfree(pReadBuff);
                                break ;
                         }
 
@@ -2273,7 +2015,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                if(Status)
                                {
                                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"copy of Ioctl buffer is failed from user space");
-                                       Status = -EFAULT;
                                        break;
                                }
 
@@ -2281,7 +2022,6 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                if(Status)
                                {
                                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"copy of control bit mask failed from user space");
-                                       Status = -EFAULT;
                                        break;
                                }
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"\n Got user defined cntrl msg bit mask :%lx", RxCntrlMsgBitMask);
@@ -2300,71 +2040,44 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
                                DevInfo.u32NVMType = Adapter->eNVMType;
                                DevInfo.u32InterfaceType = BCM_USB;
 
-                               Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER));
-                               if(Status)
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
-                                       Status = -EFAULT;
-                                       break;
-                               }
+                               if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+                                       return -EFAULT;
+
                                if(IoBuffer.OutputLength < sizeof(DevInfo))
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"User Passed buffer length is less than actural buffer size");
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"user passed buffer size :0x%lX, expected size :0x%zx",IoBuffer.OutputLength, sizeof(DevInfo));
-                                       Status = -EINVAL;
-                                       break;
-                               }
-                               Status = copy_to_user(IoBuffer.OutputBuffer, &DevInfo, sizeof(DevInfo));
-                               if(Status)
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"copying Dev info structure to user space buffer failed");
-                                       Status = -EFAULT;
-                                       break;
-                               }
+                                       return -EINVAL;
+
+                               if (copy_to_user(IoBuffer.OutputBuffer, &DevInfo, sizeof(DevInfo)))
+                                       return -EFAULT;
                        }
                        break ;
 
                        case IOCTL_BCM_TIME_SINCE_NET_ENTRY:
                        {
                                ST_TIME_ELAPSED stTimeElapsedSinceNetEntry = {0};
-                               struct timeval tv = {0} ;
 
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"IOCTL_BCM_TIME_SINCE_NET_ENTRY called");
 
-                               Status = copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER));
-                               if(Status)
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Copy of IOCTL BUFFER failed");
-                                       Status = -EFAULT;
-                                       break;
-                               }
+                               if (copy_from_user(&IoBuffer, argp, sizeof(IOCTL_BUFFER)))
+                                       return -EFAULT;
+
                                if(IoBuffer.OutputLength < sizeof(ST_TIME_ELAPSED))
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"User Passed buffer length:0x%lx is less than expected buff size :0x%zX",IoBuffer.OutputLength,sizeof(ST_TIME_ELAPSED));
-                                       Status = -EINVAL;
-                                       break;
-                               }
+                                       return -EINVAL;
 
-                               //stTimeElapsedSinceNetEntry.ul64TimeElapsedSinceNetEntry = Adapter->liTimeSinceLastNetEntry;
-                               do_gettimeofday(&tv);
-                               stTimeElapsedSinceNetEntry.ul64TimeElapsedSinceNetEntry = tv.tv_sec - Adapter->liTimeSinceLastNetEntry;
+                               stTimeElapsedSinceNetEntry.ul64TimeElapsedSinceNetEntry = get_seconds() - Adapter->liTimeSinceLastNetEntry;
 
-                               Status = copy_to_user(IoBuffer.OutputBuffer, &stTimeElapsedSinceNetEntry, sizeof(ST_TIME_ELAPSED));
-                               if(Status)
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"copying ST_TIME_ELAPSED structure to user space buffer failed");
-                                       Status = -EFAULT;
-                                       break;
-                               }
+                               if (copy_to_user(IoBuffer.OutputBuffer, &stTimeElapsedSinceNetEntry, sizeof(ST_TIME_ELAPSED)))
+                                       return -EFAULT;
 
                        }
                        break;
 
-               default:
-            BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, "wrong input %x",cmd);
-                       BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "In default ioctl %d\n", cmd);
-                        Status = STATUS_FAILURE;
+               case IOCTL_CLOSE_NOTIFICATION:
+                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL,"IOCTL_CLOSE_NOTIFICATION");
+                       break;
 
+               default:
+                       pr_info(DRV_NAME ": unknown ioctl cmd=%#x\n", cmd);
+                       Status = STATUS_FAILURE;
                        break;
        }
        return Status;
@@ -2380,59 +2093,37 @@ static struct file_operations bcm_fops = {
        .llseek = no_llseek,
 };
 
+extern struct class *bcm_class;
 
 int register_control_device_interface(PMINI_ADAPTER Adapter)
 {
+
        if(Adapter->major>0)
-       return Adapter->major;
-    Adapter->major = register_chrdev(0, "tarang", &bcm_fops);
-    if(Adapter->major < 0)
-    {
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "register_chrdev:Failed to registering WiMax control char device!");
-        return Adapter->major;
-    }
-
-       bcm_class = NULL;
-       bcm_class = class_create (THIS_MODULE, "tarang");
-       if(IS_ERR (bcm_class))
-       {
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Unable to create class\n");
-        unregister_chrdev(Adapter->major, "tarang");
-               Adapter->major = 0;
-               return -ENODEV;
+               return Adapter->major;
+
+       Adapter->major = register_chrdev(0, DEV_NAME, &bcm_fops);
+       if(Adapter->major < 0) {
+               pr_err(DRV_NAME ": could not created character device\n");
+               return Adapter->major;
        }
+
        Adapter->pstCreatedClassDevice = device_create (bcm_class, NULL,
-                                                               MKDEV(Adapter->major, 0),
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26)
-                                                               NULL    ,
-#endif
-                                                               "tarang");
+                                                       MKDEV(Adapter->major, 0), Adapter,
+                                                       DEV_NAME);
 
-       if(IS_ERR(Adapter->pstCreatedClassDevice))
-       {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "class device did not get created : %ld", PTR_ERR(Adapter->pstCreatedClassDevice) );
+       if(IS_ERR(Adapter->pstCreatedClassDevice)) {
+               pr_err(DRV_NAME ": class device create failed\n");
+               unregister_chrdev(Adapter->major, DEV_NAME);
+               return PTR_ERR(Adapter->pstCreatedClassDevice);
        }
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Got Major No: %d", Adapter->major);
-    return 0;
+                       
+       return 0;
 }
 
 void unregister_control_device_interface(PMINI_ADAPTER Adapter)
 {
-       if(Adapter->major > 0)
-       {
-        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "destroying class device");
+       if(Adapter->major > 0) {
                device_destroy (bcm_class, MKDEV(Adapter->major, 0));
+               unregister_chrdev(Adapter->major, DEV_NAME);
        }
-    if(!IS_ERR(bcm_class))
-       {
-        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "destroying created class ");
-        class_destroy (bcm_class);
-               bcm_class = NULL;
-       }
-       if(Adapter->major > 0)
-       {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,"unregistering character interface");
-        unregister_chrdev(Adapter->major, "tarang");
-       }
-
 }
index bc296982142132ad6384d13a0e84a3be24bf837b..a6ce2396c7911d7e7d6d8bace0c329d56e662332 100644 (file)
 #include "headers.h"
 
-static INT bcm_notify_event(struct notifier_block *nb, ULONG event, PVOID dev)
+struct net_device *gblpnetdev;
+
+static INT bcm_open(struct net_device *dev)
 {
-       struct net_device *ndev = (struct net_device*)dev;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
-       //PMINI_ADAPTER         Adapter = (PMINI_ADAPTER)ndev->priv;
-       if(strncmp(ndev->name,gblpnetdev->name,5)==0)
-       {
-               switch(event)
-               {
-                       case NETDEV_CHANGEADDR:
-                       case NETDEV_GOING_DOWN:
-                               /*ignore this */
-                                       break;
-                       case NETDEV_DOWN:
-                               break;
-
-                       case NETDEV_UP:
-                               break;
-
-                       case NETDEV_REGISTER:
-                                /* Increment the Reference Count for "veth0" */
-                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Register RefCount: %x\n",
-                                                                       netdev_refcnt_read(ndev));
-                                dev_hold(ndev);
-                                break;
-
-                       case NETDEV_UNREGISTER:
-                                /* Decrement the Reference Count for "veth0" */
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Unregister RefCnt: %x\n",
-                                                                       netdev_refcnt_read(ndev));
-                               dev_put(ndev);
-                               break;
-               };
+       PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
+
+       if (Adapter->fw_download_done == FALSE) {
+               pr_notice(PFX "%s: link up failed (download in progress)\n",
+                         dev->name);
+               return -EBUSY;
        }
-       return NOTIFY_DONE;
-}
 
-/* Notifier block to receive netdevice events */
-static struct notifier_block bcm_notifier_block =
-{
-       .notifier_call = bcm_notify_event,
-};
+       if (netif_msg_ifup(Adapter))
+               pr_info(PFX "%s: enabling interface\n", dev->name);
 
-struct net_device *gblpnetdev;
-/***************************************************************************************/
-/* proto-type of lower function */
-#ifdef BCM_SHM_INTERFACE
-const char *bcmVirtDeviceName="bcmeth";
-#endif
+       if (Adapter->LinkUpStatus) {
+               if (netif_msg_link(Adapter))
+                       pr_info(PFX "%s: link up\n", dev->name);
 
-static INT bcm_open(struct net_device *dev)
-{
-    PMINI_ADAPTER Adapter = NULL ; //(PMINI_ADAPTER)dev->priv;
-       Adapter = GET_BCM_ADAPTER(dev);
-    BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "======>");
-    if(Adapter->fw_download_done==FALSE)
-        return -EINVAL;
-       Adapter->if_up=1;
-       if(Adapter->LinkUpStatus == 1){
-               if(netif_queue_stopped(Adapter->dev)){
-                       netif_carrier_on(Adapter->dev);
-                       netif_start_queue(Adapter->dev);
-               }
+               netif_carrier_on(Adapter->dev);
+               netif_start_queue(Adapter->dev);
        }
 
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "<======");
-    return 0;
+       return 0;
 }
 
 static INT bcm_close(struct net_device *dev)
 {
-   PMINI_ADAPTER Adapter = NULL ;//gpadapter ;
-   Adapter = GET_BCM_ADAPTER(dev);
-    BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "=====>");
-       Adapter->if_up=0;
-       if(!netif_queue_stopped(dev)) {
-               netif_carrier_off(dev);
-           netif_stop_queue(dev);
-       }
-    BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,"<=====");
-    return 0;
+       PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
+
+       if (netif_msg_ifdown(Adapter))
+               pr_info(PFX "%s: disabling interface\n", dev->name);
+
+       netif_carrier_off(dev);
+       netif_stop_queue(dev);
+
+       return 0;
+}
+
+static u16 bcm_select_queue(struct net_device *dev, struct sk_buff *skb)
+{
+       return ClassifyPacket(netdev_priv(dev), skb);
 }
 
-static struct net_device_stats *bcm_get_stats(struct net_device *dev)
+/*******************************************************************
+* Function    -        bcm_transmit()
+*
+* Description - This is the main transmit function for our virtual
+*              interface(eth0). It handles the ARP packets. It
+*              clones this packet and then Queue it to a suitable
+*              Queue. Then calls the transmit_packet().
+*
+* Parameter   -         skb - Pointer to the socket buffer structure
+*               dev - Pointer to the virtual net device structure
+*
+*********************************************************************/
+
+static netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev)
 {
-    PLINUX_DEP_DATA pLinuxData=NULL;
-       PMINI_ADAPTER Adapter = NULL ;// gpadapter ;
-       Adapter = GET_BCM_ADAPTER(dev);
-    pLinuxData = (PLINUX_DEP_DATA)(Adapter->pvOsDepData);
-
-    //BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Dev = %p, pLinuxData = %p", dev, pLinuxData);
-       pLinuxData->netstats.rx_packets=atomic_read(&Adapter->RxRollOverCount)*64*1024+Adapter->PrevNumRecvDescs;
-       pLinuxData->netstats.rx_bytes=atomic_read(&Adapter->GoodRxByteCount)+atomic_read(&Adapter->BadRxByteCount);
-       pLinuxData->netstats.rx_dropped=atomic_read(&Adapter->RxPacketDroppedCount);
-       pLinuxData->netstats.rx_errors=atomic_read(&Adapter->RxPacketDroppedCount);
-       pLinuxData->netstats.rx_length_errors=0;
-       pLinuxData->netstats.rx_frame_errors=0;
-       pLinuxData->netstats.rx_crc_errors=0;
-       pLinuxData->netstats.tx_bytes=atomic_read(&Adapter->GoodTxByteCount);
-       pLinuxData->netstats.tx_packets=atomic_read(&Adapter->TxTotalPacketCount);
-       pLinuxData->netstats.tx_dropped=atomic_read(&Adapter->TxDroppedPacketCount);
-
-    return &(pLinuxData->netstats);
+       PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
+       u16 qindex = skb_get_queue_mapping(skb);
+
+
+       if (Adapter->device_removed || !Adapter->LinkUpStatus)
+               goto drop;
+
+       if (Adapter->TransferMode != IP_PACKET_ONLY_MODE)
+               goto drop;
+
+       if (INVALID_QUEUE_INDEX == qindex)
+               goto drop;
+
+       if (Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >=
+           SF_MAX_ALLOWED_PACKETS_TO_BACKUP)
+               return NETDEV_TX_BUSY;
+
+       /* Now Enqueue the packet */
+       if (netif_msg_tx_queued(Adapter))
+               pr_info(PFX "%s: enqueueing packet to queue %d\n",
+                       dev->name, qindex);
+
+       spin_lock(&Adapter->PackInfo[qindex].SFQueueLock);
+       Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len;
+       Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++;
+
+       *((B_UINT32 *) skb->cb + SKB_CB_LATENCY_OFFSET) = jiffies;
+       ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue,
+                     Adapter->PackInfo[qindex].LastTxQueue, skb);
+       atomic_inc(&Adapter->TotalPacketCount);
+       spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock);
+
+       /* FIXME - this is racy and incorrect, replace with work queue */
+       if (!atomic_read(&Adapter->TxPktAvail)) {
+               atomic_set(&Adapter->TxPktAvail, 1);
+               wake_up(&Adapter->tx_packet_wait_queue);
+       }
+       return NETDEV_TX_OK;
+
+ drop:
+       dev_kfree_skb(skb);
+       return NETDEV_TX_OK;
 }
+
+
+
 /**
 @ingroup init_functions
 Register other driver entry points with the kernel
 */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
-static struct net_device_ops bcmNetDevOps = {
+static const struct net_device_ops bcmNetDevOps = {
     .ndo_open          = bcm_open,
     .ndo_stop          = bcm_close,
-    .ndo_get_stats     = bcm_get_stats,
     .ndo_start_xmit    = bcm_transmit,
     .ndo_change_mtu    = eth_change_mtu,
     .ndo_set_mac_address = eth_mac_addr,
     .ndo_validate_addr = eth_validate_addr,
+    .ndo_select_queue  = bcm_select_queue,
 };
-#endif
 
-int register_networkdev(PMINI_ADAPTER Adapter)
+static struct device_type wimax_type = {
+       .name   = "wimax",
+};
+
+static int bcm_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-       int result=0;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
-       void **temp = NULL; /* actually we're *allocating* the device in alloc_etherdev */
-#endif
-       Adapter->dev = alloc_etherdev(sizeof(PMINI_ADAPTER));
-       if(!Adapter->dev)
-       {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "ERR: No Dev");
-               return -ENOMEM;
-       }
-       gblpnetdev                                                      = Adapter->dev;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
-       Adapter->dev->priv                              = Adapter;
-#else
-       temp = netdev_priv(Adapter->dev);
-       *temp = (void *)Adapter;
-#endif
-       //BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "init adapterptr: %x %x\n", (UINT)Adapter, temp);
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
-        Adapter->dev->netdev_ops                = &bcmNetDevOps;
-#else
-       Adapter->dev->open                              = bcm_open;
-       Adapter->dev->stop                      = bcm_close;
-       Adapter->dev->get_stats                 = bcm_get_stats;
-       Adapter->dev->hard_start_xmit           = bcm_transmit;
-       Adapter->dev->hard_header_len           = ETH_HLEN + LEADER_SIZE;
-#endif
-
-#ifndef BCM_SHM_INTERFACE
-       Adapter->dev->mtu                                       = MTU_SIZE; /* 1400 Bytes */
-       /* Read the MAC Address from EEPROM */
-       ReadMacAddressFromNVM(Adapter);
+       cmd->supported          = 0;
+       cmd->advertising        = 0;
+       cmd->speed              = SPEED_10000;
+       cmd->duplex             = DUPLEX_FULL;
+       cmd->port               = PORT_TP;
+       cmd->phy_address        = 0;
+       cmd->transceiver        = XCVR_INTERNAL;
+       cmd->autoneg            = AUTONEG_DISABLE;
+       cmd->maxtxpkt           = 0;
+       cmd->maxrxpkt           = 0;
+       return 0;
+}
 
+static void bcm_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+       PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
+       PS_INTERFACE_ADAPTER psIntfAdapter = Adapter->pvInterfaceAdapter;
+       struct usb_device *udev = interface_to_usbdev(psIntfAdapter->interface);
 
-       /* Register the notifier block for getting netdevice events */
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Registering netdevice notifier\n");
-       result = register_netdevice_notifier(&bcm_notifier_block);
-       if(result)
-       {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "BCM Notifier Block did not get registered");
-               Adapter->bNetdeviceNotifierRegistered = FALSE;
-               return result;
-       }
-       else
-       {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "BCM Notifier got Registered");
-               Adapter->bNetdeviceNotifierRegistered = TRUE;
-       }
+       strcpy(info->driver, DRV_NAME);
+       strcpy(info->version, DRV_VERSION);
+       snprintf(info->fw_version, sizeof(info->fw_version), "%u.%u",
+                Adapter->uiFlashLayoutMajorVersion,
+                Adapter->uiFlashLayoutMinorVersion);
 
-#else
-
-       Adapter->dev->mtu                       = CPE_MTU_SIZE;
-
-#if 0
-       //for CPE - harcode the virtual mac address
-       Adapter->dev->dev_addr[0] =  MII_WIMAX_MACADDRESS[0];
-       Adapter->dev->dev_addr[1] =  MII_WIMAX_MACADDRESS[1];
-       Adapter->dev->dev_addr[2] =  MII_WIMAX_MACADDRESS[2];
-       Adapter->dev->dev_addr[3] =  MII_WIMAX_MACADDRESS[3];
-       Adapter->dev->dev_addr[4] =  MII_WIMAX_MACADDRESS[4];
-       Adapter->dev->dev_addr[5] =  MII_WIMAX_MACADDRESS[5];
-#else
-       ReadMacAddressFromNVM(Adapter);
-#endif
-       strcpy(Adapter->dev->name, bcmVirtDeviceName); //Copy the device name
-
-#endif
-
-       result = register_netdev(Adapter->dev);
-       if (!result)
-       {
-               Adapter->bNetworkInterfaceRegistered = TRUE ;
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Beceem Network device name is %s!", Adapter->dev->name);
-       }
-       else
-       {
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Network device can not be registered!");
-               Adapter->bNetworkInterfaceRegistered = FALSE ;
-               return result;
-       }
+       usb_make_path(udev, info->bus_info, sizeof(info->bus_info));
+}
 
-#if 0
- Adapter->stDebugState.debug_level = DBG_LVL_CURR;
- Adapter->stDebugState.type =(UINT)0xffffffff;
- Adapter->stDebugState.subtype[DBG_TYPE_OTHERS] = 0xffffffff;
- Adapter->stDebugState.subtype[DBG_TYPE_RX] = 0xffffffff;
- Adapter->stDebugState.subtype[DBG_TYPE_TX] = 0xffffffff;
- Adapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0xffffffff;
+static u32 bcm_get_link(struct net_device *dev)
+{
+       PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
 
- printk("-------ps_adapter->stDebugState.type=%x\n",Adapter->stDebugState.type);
- printk("-------ps_adapter->stDebugState.subtype[DBG_TYPE_OTHERS]=%x\n",Adapter->stDebugState.subtype[DBG_TYPE_OTHERS]);
- printk("-------ps_adapter->stDebugState.subtype[DBG_TYPE_RX]=%x\n",Adapter->stDebugState.subtype[DBG_TYPE_RX]);
- printk("-------ps_adapter->stDebugState.subtype[DBG_TYPE_TX]=%x\n",Adapter->stDebugState.subtype[DBG_TYPE_TX]);
-#endif
+       return Adapter->LinkUpStatus;
+}
 
-       return 0;
+static u32 bcm_get_msglevel (struct net_device *dev)
+{
+       PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
+
+       return Adapter->msg_enable;
 }
 
-void bcm_unregister_networkdev(PMINI_ADAPTER Adapter)
+static void bcm_set_msglevel (struct net_device *dev, u32 level)
 {
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Unregistering the Net Dev...\n");
-       if(Adapter->dev && !IS_ERR(Adapter->dev) && Adapter->bNetworkInterfaceRegistered)
-               unregister_netdev(Adapter->dev);
-               /* Unregister the notifier block */
-       if(Adapter->bNetdeviceNotifierRegistered == TRUE)
-       {
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Unregistering netdevice notifier\n");
-                       unregister_netdevice_notifier(&bcm_notifier_block);
-  }
+       PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(dev);
+
+       Adapter->msg_enable = level;
 }
 
-static int bcm_init(void)
+static const struct ethtool_ops bcm_ethtool_ops = {
+       .get_settings   = bcm_get_settings,
+       .get_drvinfo    = bcm_get_drvinfo,
+       .get_link       = bcm_get_link,
+       .get_msglevel   = bcm_get_msglevel,
+       .set_msglevel   = bcm_set_msglevel,
+};
+
+int register_networkdev(PMINI_ADAPTER Adapter)
 {
+       struct net_device *net = Adapter->dev;
+       PS_INTERFACE_ADAPTER IntfAdapter = Adapter->pvInterfaceAdapter;
+       struct usb_interface *udev = IntfAdapter->interface;
+       struct usb_device *xdev = IntfAdapter->udev;
+
        int result;
-       result = InterfaceInitialize();
-       if(result)
-       {
-               printk("Initialisation failed for usbbcm");
-       }
-       else
-       {
-               printk("Initialised usbbcm");
+
+       net->netdev_ops = &bcmNetDevOps;
+       net->ethtool_ops = &bcm_ethtool_ops;
+       net->mtu = MTU_SIZE;    /* 1400 Bytes */
+       net->tx_queue_len = TX_QLEN;
+       net->flags |= IFF_NOARP;
+
+       netif_carrier_off(net);
+
+       SET_NETDEV_DEVTYPE(net, &wimax_type);
+
+       /* Read the MAC Address from EEPROM */
+       result = ReadMacAddressFromNVM(Adapter);
+       if (result != STATUS_SUCCESS) {
+               dev_err(&udev->dev,
+                       PFX "Error in Reading the mac Address: %d", result);
+               return -EIO;
        }
-       return result;
-}
 
+       result = register_netdev(net);
+       if (result)
+               return result;
 
-static void bcm_exit(void)
-{
-    printk("%s %s Calling InterfaceExit\n",__FILE__, __FUNCTION__);
-       InterfaceExit();
-    printk("%s %s InterfaceExit returned\n",__FILE__, __FUNCTION__);
-}
+       gblpnetdev = Adapter->dev;
 
-module_init(bcm_init);
-module_exit(bcm_exit);
-MODULE_LICENSE ("GPL");
+       if (netif_msg_probe(Adapter))
+               dev_info(&udev->dev, PFX "%s: register usb-%s-%s %pM\n",
+                        net->name, xdev->bus->bus_name, xdev->devpath,
+                        net->dev_addr);
 
+       return 0;
+}
 
+void unregister_networkdev(PMINI_ADAPTER Adapter)
+{
+       struct net_device *net = Adapter->dev;
+       PS_INTERFACE_ADAPTER IntfAdapter = Adapter->pvInterfaceAdapter;
+       struct usb_interface *udev = IntfAdapter->interface;
+       struct usb_device *xdev = IntfAdapter->udev;
+
+       if (netif_msg_probe(Adapter))
+               dev_info(&udev->dev, PFX "%s: unregister usb-%s%s\n",
+                        net->name, xdev->bus->bus_name, xdev->devpath);
+       unregister_netdev(Adapter->dev);
+}
index 6f388a374ddc5dde23867c49d29ba5a25f95505d..38b64e69d81a991648bf765b913195998f8d3f9e 100644 (file)
@@ -15,6 +15,7 @@ typedef enum _E_CLASSIFIER_ACTION
        eDeleteClassifier
 }E_CLASSIFIER_ACTION;
 
+static ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter,B_UINT16 tid);
 
 /************************************************************
 * Function       -     SearchSfid
@@ -28,7 +29,7 @@ typedef enum _E_CLASSIFIER_ACTION
 * Returns        - Queue index for this SFID(If matched)
                                Else Invalid Queue Index(If Not matched)
 ************************************************************/
-__inline INT SearchSfid(PMINI_ADAPTER Adapter,UINT uiSfid)
+INT SearchSfid(PMINI_ADAPTER Adapter,UINT uiSfid)
 {
        INT     iIndex=0;
        for(iIndex=(NO_OF_QUEUES-1); iIndex>=0; iIndex--)
@@ -47,26 +48,16 @@ __inline INT SearchSfid(PMINI_ADAPTER Adapter,UINT uiSfid)
 * Returns        - Queue index for the free SFID
 *                              Else returns Invalid Index.
 ****************************************************************/
-__inline INT SearchFreeSfid(PMINI_ADAPTER Adapter)
+static INT SearchFreeSfid(PMINI_ADAPTER Adapter)
 {
        UINT    uiIndex=0;
+
        for(uiIndex=0; uiIndex < (NO_OF_QUEUES-1); uiIndex++)
                if(Adapter->PackInfo[uiIndex].ulSFID==0)
                        return uiIndex;
        return NO_OF_QUEUES+1;
 }
 
-__inline int SearchVcid(PMINI_ADAPTER Adapter,unsigned short usVcid)
-{
-        int iIndex=0;
-       for(iIndex=(NO_OF_QUEUES-1);iIndex>=0;iIndex--)
-               if(Adapter->PackInfo[iIndex].usVCID_Value == usVcid)
-                       return iIndex;
-       return NO_OF_QUEUES+1;
-
-}
-
-
 /*
 Function:                              SearchClsid
 Description:                   This routinue would search Classifier  having specified ClassifierID as input parameter
@@ -76,7 +67,7 @@ Input parameters:             PMINI_ADAPTER Adapter - Adapter Context
 Return:                                        int :Classifier table index of matching entry
 */
 
-__inline int SearchClsid(PMINI_ADAPTER Adapter,ULONG ulSFID,B_UINT16  uiClassifierID)
+static int SearchClsid(PMINI_ADAPTER Adapter,ULONG ulSFID,B_UINT16  uiClassifierID)
 {
        unsigned int uiClassifierIndex = 0;
        for(uiClassifierIndex=0;uiClassifierIndex<MAX_CLASSIFIERS;uiClassifierIndex++)
@@ -94,7 +85,7 @@ __inline int SearchClsid(PMINI_ADAPTER Adapter,ULONG ulSFID,B_UINT16  uiClassifi
 This routinue would search Free available Classifier entry in classifier table.
 @return free Classifier Entry index in classifier table for specified SF
 */
-static __inline int SearchFreeClsid(PMINI_ADAPTER Adapter /**Adapter Context*/
+static int SearchFreeClsid(PMINI_ADAPTER Adapter /**Adapter Context*/
                                                )
 {
        unsigned int uiClassifierIndex = 0;
@@ -106,7 +97,7 @@ static __inline int SearchFreeClsid(PMINI_ADAPTER Adapter /**Adapter Context*/
        return MAX_CLASSIFIERS+1;
 }
 
-VOID deleteSFBySfid(PMINI_ADAPTER Adapter, UINT uiSearchRuleIndex)
+static VOID deleteSFBySfid(PMINI_ADAPTER Adapter, UINT uiSearchRuleIndex)
 {
        //deleting all the packet held in the SF
        flush_queue(Adapter,uiSearchRuleIndex);
@@ -985,7 +976,7 @@ static VOID CopyToAdapter( register PMINI_ADAPTER Adapter,          /**<Pointer to the A
 
        if(Adapter->PackInfo[uiSearchRuleIndex].pstSFIndication)
        {
-               bcm_kfree(Adapter->PackInfo[uiSearchRuleIndex].pstSFIndication);
+               kfree(Adapter->PackInfo[uiSearchRuleIndex].pstSFIndication);
                Adapter->PackInfo[uiSearchRuleIndex].pstSFIndication = NULL;
        }
        Adapter->PackInfo[uiSearchRuleIndex].pstSFIndication = pstAddIndication;
@@ -1061,12 +1052,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
                pstAddIndication->sfAuthorizedSet.u32MaxTrafficBurst);
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MinReservedTrafficRate : 0x%X",
                pstAddIndication->sfAuthorizedSet.u32MinReservedTrafficRate);
-#if 0
-       BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u32MinimumTolerableTrafficRate   : 0x%X",
-               pstAddIndication->sfAuthorizedSet.u32MinimumTolerableTrafficRate);
-       BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u32RequesttransmissionPolicy     : 0x%X",
-               pstAddIndication->sfAuthorizedSet.u32RequesttransmissionPolicy);
-#endif
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParamLength    : 0x%X",
                pstAddIndication->sfAuthorizedSet.u8VendorSpecificQoSParamLength);
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParam          : 0x%X",
@@ -1114,13 +1099,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
                pstAddIndication->sfAuthorizedSet.u8PagingPreference);
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u16UnsolicitedPollingInterval            : 0x%X",
                pstAddIndication->sfAuthorizedSet.u16UnsolicitedPollingInterval);
-#if 0
-       BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "MBSZoneIdentifierassignmentLength        : 0x%X",
-               pstAddIndication->sfAuthorizedSet.MBSZoneIdentifierassignmentLength);
-       for(uiLoopIndex=0; uiLoopIndex < MAX_STRING_LEN; uiLoopIndex++)
-               BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "MBSZoneIdentifierassignment : 0x%X",
-                       pstAddIndication->sfAuthorizedSet.MBSZoneIdentifierassignment[uiLoopIndex]);
-#endif
 
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "sfAuthorizedSet.u8HARQChannelMapping %x  %x %x ",
                                *(unsigned int*)pstAddIndication->sfAuthorizedSet.u8HARQChannelMapping,
@@ -1158,11 +1136,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
                        psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0],
                        psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1],
                        psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2]);
-#if 0
-
-               BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "u8ProtocolLength                             :0x%X ",
-                       psfCSType->cCPacketClassificationRule.u8ProtocolLength);
-#endif
 
                for(uiLoopIndex=0; uiLoopIndex < 1; uiLoopIndex++)
                        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8Protocol : 0x%02X ",
@@ -1278,14 +1251,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
                        pstAddIndication->sfAdmittedSet.u8QosParamSet);
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8TrafficPriority                        : 0x%02X",
                        pstAddIndication->sfAdmittedSet.u8TrafficPriority);
-#if 0
-       BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "u32MaxSustainedTrafficRate   : 0x%02X",
-                       ntohl(pstAddIndication->sfAdmittedSet.u32MaxSustainedTrafficRate));
-       BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "u32MinimumTolerableTrafficRate       : 0x%X",
-               pstAddIndication->sfAdmittedSet.u32MinimumTolerableTrafficRate);
-       BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "u32RequesttransmissionPolicy : 0x%X",
-               pstAddIndication->sfAdmittedSet.u32RequesttransmissionPolicy);
-#endif
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u32MaxTrafficBurst                       : 0x%X",
                        pstAddIndication->sfAdmittedSet.u32MaxTrafficBurst);
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u32MinReservedTrafficRate        : 0x%X",
@@ -1339,13 +1304,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
                pstAddIndication->sfAdmittedSet.u16TimeBase);
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8PagingPreference               : 0x%X",
                pstAddIndication->sfAdmittedSet.u8PagingPreference);
-#if 0
-       BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "MBSZoneIdentifierassignmentLength        : 0x%X",
-               pstAddIndication->sfAdmittedSet.MBSZoneIdentifierassignmentLength);
-       for(uiLoopIndex=0; uiLoopIndex < MAX_STRING_LEN; uiLoopIndex++)
-               BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "MBSZoneIdentifierassignment : 0x%X",
-       pstAddIndication->sfAdmittedSet.MBSZoneIdentifierassignment[uiLoopIndex]);
-#endif
 
 
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8TrafficIndicationPreference    : 0x%02X",
@@ -1378,11 +1336,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
                        psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0],
                        psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1],
                        psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2]);
-#if 0
-
-               BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8ProtocolLength                 :0x%02X ",
-                       psfCSType->cCPacketClassificationRule.u8ProtocolLength);
-#endif
                for(uiLoopIndex=0; uiLoopIndex < 1; uiLoopIndex++)
                        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8Protocol: 0x%02X ",
                        psfCSType->cCPacketClassificationRule.u8Protocol);
@@ -1497,20 +1450,10 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
                pstAddIndication->sfActiveSet.u8QosParamSet);
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8TrafficPriority                        : 0x%02X",
                pstAddIndication->sfActiveSet.u8TrafficPriority);
-#if 0
-       BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "u32MaxSustainedTrafficRate   : 0x%02X",
-               ntohl(pstAddIndication->sfActiveSet.u32MaxSustainedTrafficRate));
-#endif
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u32MaxTrafficBurst                       : 0x%X",
                pstAddIndication->sfActiveSet.u32MaxTrafficBurst);
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u32MinReservedTrafficRate        : 0x%X",
                pstAddIndication->sfActiveSet.u32MinReservedTrafficRate);
-#if 0
-       BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "u32MinimumTolerableTrafficRate       : 0x%X",
-               pstAddIndication->sfActiveSet.u32MinimumTolerableTrafficRate);
-       BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "u32RequesttransmissionPolicy : 0x%X",
-               pstAddIndication->sfActiveSet.u32RequesttransmissionPolicy);
-#endif
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8VendorSpecificQoSParamLength   : 0x%02X",
                pstAddIndication->sfActiveSet.u8VendorSpecificQoSParamLength);
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  "u8VendorSpecificQoSParam         : 0x%02X",
@@ -1558,13 +1501,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
                pstAddIndication->sfActiveSet.u16TimeBase);
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8PagingPreference              : 0x%X",
                pstAddIndication->sfActiveSet.u8PagingPreference);
-#if 0
-       BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " MBSZoneIdentifierassignmentLength       : 0x%X",
-               pstAddIndication->sfActiveSet.MBSZoneIdentifierassignmentLength);
-       for(uiLoopIndex=0; uiLoopIndex < MAX_STRING_LEN; uiLoopIndex++)
-               BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " MBSZoneIdentifierassignment : 0x%X",
-               pstAddIndication->sfActiveSet.MBSZoneIdentifierassignment[uiLoopIndex]);
-#endif
 
 
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8TrafficIndicationPreference   : 0x%X",
@@ -1597,11 +1533,6 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
                        psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0],
                        psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1],
                        psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2]);
-#if 0
-
-               BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  " u8ProtocolLength                            :0x%X ",
-                       psfCSType->cCPacketClassificationRule.u8ProtocolLength);
-#endif
                for(uiLoopIndex=0; uiLoopIndex < 1; uiLoopIndex++)
                        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,  " u8Protocol      : 0x%X ",
                        psfCSType->cCPacketClassificationRule.u8Protocol);
@@ -1706,12 +1637,8 @@ static inline ULONG RestoreSFParam(PMINI_ADAPTER Adapter, ULONG ulAddrSFParamSet
                return 0;
        }
        ulAddrSFParamSet = ntohl(ulAddrSFParamSet);
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  " RestoreSFParam: Total Words of DSX Message To Read: 0x%zx  From Target At : 0x%lx ",
-                               nBytesToRead/sizeof(ULONG),ulAddrSFParamSet);
-       BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "sizeof(stServiceFlowParamSI) = %zx", sizeof(stServiceFlowParamSI));
 
        //Read out the SF Param Set At the indicated Location
-       BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "nBytesToRead = %x", nBytesToRead);
        if(rdm(Adapter, ulAddrSFParamSet, (PUCHAR)pucDestBuffer, nBytesToRead) < 0)
                return STATUS_FAILURE;
 
@@ -1719,7 +1646,7 @@ static inline ULONG RestoreSFParam(PMINI_ADAPTER Adapter, ULONG ulAddrSFParamSet
 }
 
 
-static __inline ULONG StoreSFParam(PMINI_ADAPTER Adapter,PUCHAR pucSrcBuffer,ULONG  ulAddrSFParamSet)
+static ULONG StoreSFParam(PMINI_ADAPTER Adapter,PUCHAR pucSrcBuffer,ULONG  ulAddrSFParamSet)
 {
     UINT       nBytesToWrite = sizeof(stServiceFlowParamSI);
        UINT    uiRetVal =0;
@@ -1728,9 +1655,6 @@ static __inline ULONG StoreSFParam(PMINI_ADAPTER Adapter,PUCHAR pucSrcBuffer,ULO
        {
                return 0;
        }
-       BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  " StoreSFParam: Total Words of DSX Message To Write: 0x%zX  To Target At : 0x%lX ",(nBytesToWrite/sizeof(ULONG)),ulAddrSFParamSet);
-
-       BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  "WRM  with %x bytes",nBytesToWrite);
 
        uiRetVal = wrm(Adapter,ulAddrSFParamSet,(PUCHAR)pucSrcBuffer, nBytesToWrite);
        if(uiRetVal < 0) {
@@ -1844,7 +1768,7 @@ ULONG StoreCmControlResponseMessage(PMINI_ADAPTER Adapter,PVOID pvBuffer,UINT *p
 
        (*puBufferLength) = sizeof(stLocalSFAddIndication);
        *(stLocalSFAddIndication *)pvBuffer = *pstAddIndication;
-       bcm_kfree(pstAddIndication);
+       kfree(pstAddIndication);
        return 1;
 }
 
@@ -1931,7 +1855,7 @@ static inline stLocalSFAddIndicationAlt
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "============================================================");
        return pstAddIndicationDest;
 failed_restore_sf_param:
-       bcm_kfree(pstAddIndicationDest);
+       kfree(pstAddIndicationDest);
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "<=====" );
        return NULL;
 }
@@ -1988,7 +1912,7 @@ ULONG SetUpTargetDsxBuffers(PMINI_ADAPTER Adapter)
        return 1;
 }
 
-ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter,B_UINT16 tid)
+static ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter,B_UINT16 tid)
 {
        ULONG  ulTargetDSXBufferAddress;
        ULONG  ulTargetDsxBufferIndexToUse,ulMaxTry;
@@ -2049,7 +1973,7 @@ INT FreeAdapterDsxBuffer(PMINI_ADAPTER Adapter)
 {
        if(Adapter->caDsxReqResp)
        {
-               bcm_kfree(Adapter->caDsxReqResp);
+               kfree(Adapter->caDsxReqResp);
        }
        return 0;
 
@@ -2102,7 +2026,7 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter,  /**<Pointer to the Adap
 
                        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL,  " VCID = %x", ntohs(pstAddIndication->u16VCID));
                        CopyBufferToControlPacket(Adapter,(PVOID)Adapter->caDsxReqResp);
-                       bcm_kfree(pstAddIndication);
+                       kfree(pstAddIndication);
                }
                break;
                case DSA_RSP:
@@ -2118,7 +2042,7 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter,  /**<Pointer to the Adap
                case DSA_ACK:
                {
                        UINT uiSearchRuleIndex=0;
-                       struct timeval tv = {0};
+
                        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "VCID:0x%X",
                                ntohs(pstAddIndication->u16VCID));
             uiSearchRuleIndex=SearchFreeSfid(Adapter);
@@ -2169,7 +2093,7 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter,  /**<Pointer to the Adap
                                        Adapter->PackInfo[uiSearchRuleIndex].bActive=FALSE;
                     Adapter->PackInfo[uiSearchRuleIndex].bValid=FALSE;
                                        Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value=0;
-                                       bcm_kfree(pstAddIndication);
+                                       kfree(pstAddIndication);
                                }
 
                                else if(psfLocalSet->bValid && (pstAddIndication->u8CC == 0))
@@ -2200,14 +2124,13 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter,  /**<Pointer to the Adap
                                                        if(!Adapter->LinkUpStatus)
                                                        {
                                                                netif_carrier_on(Adapter->dev);
-                                                       netif_start_queue(Adapter->dev);
+                                                               netif_start_queue(Adapter->dev);
                                                                Adapter->LinkUpStatus = 1;
-                                                               do_gettimeofday(&tv);
-
+                                                               if (netif_msg_link(Adapter))
+                                                                       pr_info(PFX "%s: link up\n", Adapter->dev->name);
                                                                atomic_set(&Adapter->TxPktAvail, 1);
                                                                wake_up(&Adapter->tx_packet_wait_queue);
-                                                               Adapter->liTimeSinceLastNetEntry = tv.tv_sec;
-                                                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "============Tx Service Flow Created!");
+                                                               Adapter->liTimeSinceLastNetEntry = get_seconds();
                                                        }
                                                }
                                        }
@@ -2218,13 +2141,13 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter,  /**<Pointer to the Adap
                                        Adapter->PackInfo[uiSearchRuleIndex].bActive=FALSE;
                     Adapter->PackInfo[uiSearchRuleIndex].bValid=FALSE;
                                        Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value=0;
-                                       bcm_kfree(pstAddIndication);
+                                       kfree(pstAddIndication);
                                }
                        }
                        else
                        {
                                BCM_DEBUG_PRINT( Adapter,DBG_TYPE_PRINTK, 0, 0, "DSA ACK did not get valid SFID");
-                               bcm_kfree(pstAddIndication);
+                               kfree(pstAddIndication);
                                return FALSE;
                        }
                }
@@ -2239,7 +2162,7 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter,  /**<Pointer to the Adap
                        ((stLocalSFChangeIndicationAlt*)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSC_RSP;
 
                        CopyBufferToControlPacket(Adapter,(PVOID)Adapter->caDsxReqResp);
-                       bcm_kfree(pstAddIndication);
+                       kfree(pstAddIndication);
                }
                break;
                case DSC_RSP:
@@ -2312,13 +2235,13 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter,  /**<Pointer to the Adap
                                else if(pstChangeIndication->u8CC == 6)
                                {
                                        deleteSFBySfid(Adapter,uiSearchRuleIndex);
-                                       bcm_kfree(pstAddIndication);
+                                       kfree(pstAddIndication);
                                }
                        }
                        else
                        {
                                BCM_DEBUG_PRINT( Adapter,DBG_TYPE_PRINTK, 0, 0, "DSC ACK did not get valid SFID");
-                               bcm_kfree(pstAddIndication);
+                               kfree(pstAddIndication);
                                return FALSE;
                        }
                }
@@ -2355,7 +2278,7 @@ BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter,  /**<Pointer to the Adap
                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "DSD ACK Rcd, let App handle it\n");
                        break;
        default:
-               bcm_kfree(pstAddIndication);
+               kfree(pstAddIndication);
                return FALSE ;
        }
        return TRUE;
index 847782c3765b55eea422aea7a27e2b4dce9dbf44..8f689769b4ba78b6c417619652a08a14a8ad7f3b 100644 (file)
@@ -150,8 +150,6 @@ typedef struct stLocalSFChangeIndicationAlt{
 
 ULONG StoreCmControlResponseMessage(PMINI_ADAPTER Adapter,PVOID pvBuffer,UINT *puBufferLength);
 
-ULONG GetNextTargetBufferLocation(PMINI_ADAPTER Adapter,B_UINT16 tid);
-
 INT AllocAdapterDsxBuffer(PMINI_ADAPTER Adapter);
 
 INT FreeAdapterDsxBuffer(PMINI_ADAPTER Adapter);
@@ -159,7 +157,6 @@ ULONG SetUpTargetDsxBuffers(PMINI_ADAPTER Adapter);
 
 BOOLEAN CmControlResponseMessage(PMINI_ADAPTER Adapter,PVOID pvBuffer);
 
-VOID deleteSFBySfid(PMINI_ADAPTER Adapter, UINT uiSearchRuleIndex);
 
 #pragma pack (pop)
 
index 8907e211d483fa3be8f318b8b81e1ea86e81c3da..411f02a6b6ea67dc2471a9bb1a790f763ed987c8 100644 (file)
@@ -1,6 +1,5 @@
 #include "headers.h"
 
-#ifndef BCM_SHM_INTERFACE
 
 
 #define DDR_DUMP_INTERNAL_DEVICE_MEMORY 0xBFC02B00
@@ -188,17 +187,6 @@ static DDR_SET_NODE asDPLL_266MHZ[] = {
                                         {0x0f000840,0x0FFF1B00},
                                         {0x0f000870,0x00000002}
                                                                          };
-#if 0
-static DDR_SET_NODE asDPLL_800MHZ[] = {
-                                                                               {0x0f000810,0x00000F95},
-                                                                               {0x0f000810,0x00000F95},
-                                        {0x0f000810,0x00000F95},
-                                        {0x0f000820,0x03F1365B},
-                                        {0x0f000840,0x0FFF0000},
-                                        {0x0f000880,0x000003DD},
-                                        {0x0f000860,0x00000000}
-                                                                         };
-#endif
 
 #define T3B_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 11  //index for 0x0F007000
 static DDR_SET_NODE asT3B_DDRSetting133MHz[] = {//      # DPLL Clock Setting
@@ -1298,5 +1286,4 @@ int download_ddr_settings(PMINI_ADAPTER Adapter)
        return retval;
 }
 
-#endif
 
diff --git a/drivers/staging/bcm/Debug.c b/drivers/staging/bcm/Debug.c
deleted file mode 100644 (file)
index 2703f30..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#include "headers.h"
-
-static UINT current_debug_level=BCM_SCREAM;
-
-int bcm_print_buffer( UINT debug_level, const char *function_name,
-                                 char *file_name, int line_number, unsigned char *buffer, int bufferlen, enum _BASE_TYPE base)
-{
-       static const char * const buff_dump_base[] = {
-               "DEC", "HEX", "OCT", "BIN"
-       };
-       if(debug_level>=current_debug_level)
-       {
-               int i=0;
-               printk("\n%s:%s:%d:Buffer dump of size 0x%x in the %s:\n", file_name, function_name, line_number, bufferlen, buff_dump_base[1]);
-               for(;i<bufferlen;i++)
-               {
-                       if(i && !(i%16) )
-                               printk("\n");
-                       switch(base)
-                       {
-                               case BCM_BASE_TYPE_DEC:
-                                       printk("%03d ", buffer[i]);
-                                       break;
-                               case BCM_BASE_TYPE_OCT:
-                                       printk("%0x03o ", buffer[i]);
-                                       break;
-                               case BCM_BASE_TYPE_BIN:
-                                       printk("%02x ", buffer[i]);
-                                       break;
-                               case BCM_BASE_TYPE_HEX:
-                               default:
-                                       printk("%02X ", buffer[i]);
-                                       break;
-                       }
-               }
-               printk("\n");
-       }
-       return 0;
-}
-
-
index 3d788b59ab5787e6f78db8da53d410320c72710a..3138729cf34fab1595349055e1c48492b926e001 100644 (file)
@@ -9,34 +9,6 @@
 #include <linux/string.h>
 #define NONE 0xFFFF
 
-typedef enum _BASE_TYPE
-{
-       BCM_BASE_TYPE_DEC,
-       BCM_BASE_TYPE_OCT,
-       BCM_BASE_TYPE_BIN,
-       BCM_BASE_TYPE_HEX,
-       BCM_BASE_TYPE_NONE,
-} BASE_TYPE, *PBASE_TYPE;
-
-int bcm_print_buffer( UINT debug_level, const char *function_name,
-                                 char *file_name, int line_number, unsigned char *buffer, int bufferlen, BASE_TYPE base);
-
-#ifdef BCM_SHM_INTERFACE
-#define CPE_VIRTUAL_ERROR_CODE_BASE_ADDR               (0xBFC02E00 + 0x4C)
-// ERROR codes for debugging
-extern unsigned char u32ErrorCounter ;
-#define ERROR_DEVICE_REMOVED  0x1
-#define ERROR_LEADER_LENGTH_ZERO  0x2
-#define ERROR_LEADER_LENGTH_CORRUPTED  0x3
-#define ERROR_NO_SKBUFF  0x4
-
-#define ERROR_DL_MODULE 0xaa000000
-extern void  CPE_ERROR_LOG(unsigned int module,unsigned int code);
-
-#endif
-
-
-
 
 //--------------------------------------------------------------------------------
 
@@ -242,44 +214,34 @@ typedef struct _S_BCM_DEBUG_STATE {
 
 //--- Only for direct printk's; "hidden" to API.
 #define DBG_TYPE_PRINTK                3
-#define PRINTKS_ON                     1       // "hidden" from API, set to 0 to turn off all printk's
-
-#define BCM_DEBUG_PRINT(Adapter, Type, SubType, dbg_level, string, args...) do { \
-       if ((DBG_TYPE_PRINTK == Type) && (PRINTKS_ON)) {        \
-               printk ("%s:" string, __FUNCTION__, ##args);    \
-               printk("\n");   \
-       } else if (!Adapter)                    \
-               ;                                                       \
-       else {                                                  \
-               if (((dbg_level & DBG_LVL_BITMASK) <= Adapter->stDebugState.debug_level) &&     \
-                  ((Type & Adapter->stDebugState.type) && (SubType & Adapter->stDebugState.subtype[Type]))) { \
-                               if (dbg_level & DBG_NO_FUNC_PRINT)              \
-                                       printk (string, ##args);                                                \
-                               else    \
-                                       {                                                                                               \
-                                       printk ("%s:" string, __FUNCTION__, ##args);    \
-                                       printk("\n"); \
-                                       } \
-               }       \
-               }       \
-} while (0)
 
-#define BCM_DEBUG_PRINT_BUFFER(Adapter, Type, SubType, dbg_level,  buffer, bufferlen) do { \
-               if ((DBG_TYPE_PRINTK == Type) && (PRINTKS_ON)) {        \
-                       bcm_print_buffer( dbg_level, __FUNCTION__, __FILE__, __LINE__, buffer, bufferlen, BCM_BASE_TYPE_HEX);   \
-               } else if (!Adapter)                    \
-                       ;                                                       \
-               else {                                                  \
-                       if (((dbg_level & DBG_LVL_BITMASK) <= Adapter->stDebugState.debug_level)  && \
-                          ((Type & Adapter->stDebugState.type) && (SubType & Adapter->stDebugState.subtype[Type]))) { \
-                                       if (dbg_level & DBG_NO_FUNC_PRINT)              \
-                                               bcm_print_buffer( dbg_level, NULL, NULL, __LINE__, buffer, bufferlen, BCM_BASE_TYPE_HEX);                                               \
-                                       else                                                                                            \
-                                               bcm_print_buffer( dbg_level, __FUNCTION__, __FILE__, __LINE__, buffer, bufferlen, BCM_BASE_TYPE_HEX);   \
-                       }       \
-               }       \
+#define BCM_DEBUG_PRINT(Adapter, Type, SubType, dbg_level, string, args...) \
+       do {                                                            \
+               if (DBG_TYPE_PRINTK == Type)                            \
+                       pr_info("%s:" string, __func__, ##args);        \
+               else if (Adapter &&                                     \
+                        (dbg_level & DBG_LVL_BITMASK) <= Adapter->stDebugState.debug_level && \
+                        (Type & Adapter->stDebugState.type) &&         \
+                        (SubType & Adapter->stDebugState.subtype[Type])) { \
+                       if (dbg_level & DBG_NO_FUNC_PRINT)              \
+                               printk(KERN_DEBUG string, ##args);      \
+                       else                                            \
+                               printk(KERN_DEBUG "%s:" string, __func__, ##args);      \
+               }                                                       \
        } while (0)
 
+#define BCM_DEBUG_PRINT_BUFFER(Adapter, Type, SubType, dbg_level,  buffer, bufferlen) do { \
+       if (DBG_TYPE_PRINTK == Type ||                                  \
+           (Adapter &&                                                 \
+            (dbg_level & DBG_LVL_BITMASK) <= Adapter->stDebugState.debug_level  && \
+            (Type & Adapter->stDebugState.type) &&                     \
+            (SubType & Adapter->stDebugState.subtype[Type]))) {        \
+               printk(KERN_DEBUG "%s:\n", __func__);                   \
+               print_hex_dump(KERN_DEBUG, " ", DUMP_PREFIX_OFFSET,     \
+                              16, 1, buffer, bufferlen, false);        \
+       }                                                               \
+} while(0)
+
 
 #define BCM_SHOW_DEBUG_BITMAP(Adapter) do { \
        int i;                                                                  \
index 7b2ec28a4bc1204f7e1242d93317445b934d1928..2b1e9e17e11ccf4a782599b21a8d2f229e46ab34 100644 (file)
@@ -11,8 +11,7 @@ When a control packet is received, analyze the
 Enqueue the control packet for Application.
 @return None
 */
-VOID handle_rx_control_packet(PMINI_ADAPTER Adapter,   /**<Pointer to the Adapter structure*/
-                                                               struct sk_buff *skb)                            /**<Pointer to the socket buffer*/
+static VOID handle_rx_control_packet(PMINI_ADAPTER Adapter, struct sk_buff *skb)
 {
        PPER_TARANG_DATA        pTarang = NULL;
        BOOLEAN HighPriorityMessage = FALSE;
@@ -20,8 +19,10 @@ VOID handle_rx_control_packet(PMINI_ADAPTER Adapter,         /**<Pointer to the Adapter
        CHAR cntrl_msg_mask_bit = 0;
        BOOLEAN drop_pkt_flag = TRUE ;
        USHORT usStatus = *(PUSHORT)(skb->data);
-       BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "=====>");
-       /* Get the Leader field */
+
+       if (netif_msg_pktdata(Adapter))
+               print_hex_dump(KERN_DEBUG, PFX "rx control: ", DUMP_PREFIX_NONE,
+                              16, 1, skb->data, skb->len, 0);
 
        switch(usStatus)
        {
@@ -134,7 +135,7 @@ VOID handle_rx_control_packet(PMINI_ADAPTER Adapter,        /**<Pointer to the Adapter
     }
        up(&Adapter->RxAppControlQueuelock);
     wake_up(&Adapter->process_read_wait_queue);
-    bcm_kfree_skb(skb);
+    dev_kfree_skb(skb);
        BCM_DEBUG_PRINT( Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "After wake_up_interruptible");
 }
 
@@ -185,33 +186,7 @@ int control_packet_handler  (PMINI_ADAPTER Adapter  /**< pointer to adapter obje
                        {
                                DEQUEUEPACKET(Adapter->RxControlHead,Adapter->RxControlTail);
 //                             Adapter->RxControlHead=ctrl_packet->next;
-                               ((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats.rx_packets++;
-                               ((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats.rx_bytes+=
-                               ((PLEADER)ctrl_packet->data)->PLength;
-                       }
-                       #if 0  //Idle mode debug profiling...
-                       if(*(PUSHORT)ctrl_packet->data == IDLE_MODE_STATUS)
-                       {
-                               puiBuffer = (PUINT)(ctrl_packet->data +sizeof(USHORT));
-                               if((ntohl(*puiBuffer) == GO_TO_IDLE_MODE_PAYLOAD))
-                               {
-                                       memset(&tv, 0, sizeof(tv));
-                                       do_gettimeofday(&tv);
-                                       if((ntohl(*(puiBuffer+1)) == 0))
-                                       {
-                                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "IdleMode Wake-up Msg from f/w at time :%ld ms", tv.tv_sec *1000 + tv.tv_usec /1000);
-                                       }
-                                       else
-                                       {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "IdleMode req Msg from f/w at time :%ld ms", tv.tv_sec *1000 + tv.tv_usec /1000);
-                                       }
-                               }
-                               else if((ntohl(*puiBuffer) == IDLE_MODE_SF_UPDATE_MSG))
-                               {
-                                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, "GOT IDLE_MODE_SF_UPDATE MSG at time :%ld ms", tv.tv_sec *1000 + tv.tv_usec /1000);
-                               }
                        }
-                       #endif
 
                        spin_unlock_irqrestore (&Adapter->control_queue_lock, flags);
                        handle_rx_control_packet(Adapter, ctrl_packet);
@@ -234,7 +209,7 @@ INT flushAllAppQ(void)
                {
                        PacketToDrop=pTarang->RxAppControlHead;
                        DEQUEUEPACKET(pTarang->RxAppControlHead,pTarang->RxAppControlTail);
-                       bcm_kfree_skb(PacketToDrop);
+                       dev_kfree_skb(PacketToDrop);
                }
                pTarang->AppCtrlQueueLen = 0;
                //dropped contrl packet statistics also should be reset.
diff --git a/drivers/staging/bcm/HostMibs.h b/drivers/staging/bcm/HostMibs.h
deleted file mode 100644 (file)
index 28a5783..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef _HOST_MIBS_H
-#define _HOST_MIBS_H
-
-INT ProcessGetHostMibs(PMINI_ADAPTER Adapter,
-                                                 PVOID ioBuffer,
-                                                 ULONG inputBufferLength);
-#endif
index 5ec3b896c6a7cec6b5d8a607ff2d213cea549525..91b6fbe33c9160f1f130e50e7211ed052ee5c03c 100644 (file)
@@ -1,5 +1,9 @@
 #include "headers.h"
 
+static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header);
+static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header);
+static VOID DumpIpv6Header(IPV6Header *pstIpv6Header);
+
 static UCHAR * GetNextIPV6ChainedHeader(UCHAR **ppucPayload,UCHAR *pucNextHeader,BOOLEAN *bParseDone,USHORT *pusPayloadLength)
 {
        UCHAR *pucRetHeaderPtr = NULL;
@@ -257,7 +261,7 @@ USHORT      IpVersion6(PMINI_ADAPTER Adapter, /**< Pointer to the driver control stru
 }
 
 
-BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header)
+static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header)
 {
        UINT uiLoopIndex=0;
        UINT  uiIpv6AddIndex=0;
@@ -310,7 +314,7 @@ BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pst
        return FALSE;
 }
 
-BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header)
+static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header)
 {
        UINT uiLoopIndex=0;
        UINT  uiIpv6AddIndex=0;
@@ -376,7 +380,7 @@ VOID DumpIpv6Address(ULONG *puIpv6Address)
 
 }
 
-VOID DumpIpv6Header(IPV6Header *pstIpv6Header)
+static VOID DumpIpv6Header(IPV6Header *pstIpv6Header)
 {
        UCHAR ucVersion;
        UCHAR  ucPrio ;
index b93f7902e28353409a918a22dfda6411ed9b03fe..a0db5a1de763ea7a7d0bd0a8cccd21771ebf630f 100644 (file)
@@ -101,15 +101,12 @@ typedef enum _E_IPADDR_CONTEXT
 
 
 //Function Prototypes
-BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header);
-BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header);
 
 USHORT IpVersion6(PMINI_ADAPTER Adapter, /**< Pointer to the driver control structure */
                                        PVOID pcIpHeader, /**<Pointer to the IP Hdr of the packet*/
                                        S_CLASSIFIER_RULE *pstClassifierRule );
 
 VOID DumpIpv6Address(ULONG *puIpv6Address);
-VOID DumpIpv6Header(IPV6Header *pstIpv6Header);
 
 extern BOOLEAN MatchSrcPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushSrcPort);
 extern BOOLEAN MatchDestPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushSrcPort);
index 60c0f29f3eef03d02cd1a661247785e27c5992e3..1fc36a15f187e62e964a0ec071b2073a154d1153 100644 (file)
@@ -1,6 +1,5 @@
 #include "headers.h"
 
-#ifndef BCM_SHM_INTERFACE
 
 int InterfaceFileDownload( PVOID arg,
                         struct file *flp,
@@ -49,7 +48,7 @@ int InterfaceFileDownload( PVOID arg,
         on_chip_loc+=MAX_TRANSFER_CTRL_BYTE_USB;
        }/* End of for(;;)*/
 
-       bcm_kfree(buff);
+       kfree(buff);
     return errno;
 }
 
@@ -70,8 +69,8 @@ int InterfaceFileReadbackFromChip( PVOID arg,
     buff_readback=(PCHAR)kmalloc(MAX_TRANSFER_CTRL_BYTE_USB , GFP_DMA);
     if(!buff || !buff_readback)
     {
-        bcm_kfree(buff);
-        bcm_kfree(buff_readback);
+        kfree(buff);
+        kfree(buff_readback);
 
         return -ENOMEM;
     }
@@ -138,8 +137,8 @@ int InterfaceFileReadbackFromChip( PVOID arg,
         on_chip_loc+=MAX_TRANSFER_CTRL_BYTE_USB;
     }/* End of while(1)*/
 exit:
-    bcm_kfree(buff);
-    bcm_kfree(buff_readback);
+    kfree(buff);
+    kfree(buff_readback);
        return Status;
 }
 
@@ -165,7 +164,7 @@ static int bcm_download_config_file(PMINI_ADAPTER Adapter,
                        psFwInfo->pvMappedFirmwareAddress, psFwInfo->u32FirmwareLength);
        if(retval)
        {
-               bcm_kfree (Adapter->pstargetparams);
+               kfree(Adapter->pstargetparams);
                Adapter->pstargetparams = NULL;
                return -EFAULT;
        }
@@ -231,41 +230,6 @@ static int bcm_download_config_file(PMINI_ADAPTER Adapter,
 
        return retval;
 }
-#if 0
-static int bcm_download_buffer(PMINI_ADAPTER Adapter,
-       unsigned char *mappedbuffer, unsigned int u32FirmwareLength,
-       unsigned long u32StartingAddress)
-{
-    char            *buff=NULL;
-    unsigned int    len = 0;
-       int                     retval = STATUS_SUCCESS;
-       buff = kzalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_KERNEL);
-
-       len = u32FirmwareLength;
-
-       while(u32FirmwareLength)
-       {
-               len = MIN_VAL (u32FirmwareLength, MAX_TRANSFER_CTRL_BYTE_USB);
-               if(STATUS_SUCCESS != (retval = copy_from_user(buff,
-                               (unsigned char *)mappedbuffer, len)))
-               {
-                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "copy_from_user failed\n");
-                       break;
-               }
-               retval = wrm (Adapter, u32StartingAddress, buff, len);
-               if(retval)
-               {
-                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "wrm failed\n");
-                       break;
-               }
-               u32StartingAddress      += len;
-               u32FirmwareLength       -= len;
-               mappedbuffer            +=len;
-       }
-       bcm_kfree(buff);
-       return retval;
-}
-#endif
 static int bcm_compare_buff_contents(unsigned char *readbackbuff,
        unsigned char *buff,unsigned int len)
 {
@@ -297,58 +261,6 @@ static int bcm_compare_buff_contents(unsigned char *readbackbuff,
        }
        return retval;
 }
-#if 0
-static int bcm_buffer_readback(PMINI_ADAPTER Adapter,
-       unsigned char *mappedbuffer, unsigned int u32FirmwareLength,
-       unsigned long u32StartingAddress)
-{
-       unsigned char *buff = NULL;
-       unsigned char *readbackbuff = NULL;
-       unsigned int  len = u32FirmwareLength;
-       int retval = STATUS_SUCCESS;
-
-    buff=(unsigned char *)kzalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_KERNEL);
-       if(NULL == buff)
-               return -ENOMEM;
-       readbackbuff =  (unsigned char *)kzalloc(MAX_TRANSFER_CTRL_BYTE_USB,
-                                       GFP_KERNEL);
-       if(NULL == readbackbuff)
-       {
-               bcm_kfree(buff);
-               return -ENOMEM;
-       }
-       while (u32FirmwareLength && !retval)
-       {
-               len = MIN_VAL (u32FirmwareLength, MAX_TRANSFER_CTRL_BYTE_USB);
-
-               /* read from the appl buff and then read from the target, compare */
-               if(STATUS_SUCCESS != (retval = copy_from_user(buff,
-                               (unsigned char *)mappedbuffer, len)))
-               {
-                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "copy_from_user failed\n");
-                       break;
-               }
-               retval = rdm (Adapter, u32StartingAddress, readbackbuff, len);
-               if(retval)
-               {
-                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "rdm failed\n");
-                       break;
-               }
-
-               if (STATUS_SUCCESS !=
-                       (retval = bcm_compare_buff_contents (readbackbuff, buff, len)))
-               {
-                       break;
-               }
-               u32StartingAddress      += len;
-               u32FirmwareLength       -= len;
-               mappedbuffer            +=len;
-       }/* end of while (u32FirmwareLength && !retval) */
-       bcm_kfree(buff);
-       bcm_kfree(readbackbuff);
-       return retval;
-}
-#endif
 int bcm_ioctl_fw_download(PMINI_ADAPTER Adapter, FIRMWARE_INFO *psFwInfo)
 {
        int retval = STATUS_SUCCESS;
@@ -389,23 +301,6 @@ int bcm_ioctl_fw_download(PMINI_ADAPTER Adapter, FIRMWARE_INFO *psFwInfo)
                        goto error ;
                }
 
-               #if 0
-               retval = bcm_download_buffer(Adapter,
-                               (unsigned char *)psFwInfo->pvMappedFirmwareAddress,
-                               psFwInfo->u32FirmwareLength, psFwInfo->u32StartingAddress);
-               if(retval != STATUS_SUCCESS)
-               {
-                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "User space buffer download fails....");
-               }
-               retval = bcm_buffer_readback (Adapter,
-                               (unsigned char *)psFwInfo->pvMappedFirmwareAddress,
-                               psFwInfo->u32FirmwareLength, psFwInfo->u32StartingAddress);
-
-               if(retval != STATUS_SUCCESS)
-               {
-                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "read back verifier failed ....");
-               }
-               #endif
                retval = buffDnldVerify(Adapter,
                                        buff,
                                        psFwInfo->u32FirmwareLength,
@@ -417,7 +312,7 @@ int bcm_ioctl_fw_download(PMINI_ADAPTER Adapter, FIRMWARE_INFO *psFwInfo)
                }
        }
 error:
-       bcm_kfree(buff);
+       kfree(buff);
        return retval;
 }
 
@@ -480,7 +375,7 @@ static INT buffRdbkVerify(PMINI_ADAPTER Adapter,
                u32FirmwareLength       -= len;
                mappedbuffer            +=len;
        }/* end of while (u32FirmwareLength && !retval) */
-       bcm_kfree(readbackbuff);
+       kfree(readbackbuff);
        return retval;
 }
 
@@ -506,5 +401,4 @@ error:
        return status;
 }
 
-#endif
 
index 0750382733ff098432d0e448059b3555868c0710..bf5c0ad86610936a20f715ba2d7c004bfec2b86a 100644 (file)
@@ -98,14 +98,6 @@ int InterfaceIdleModeRespond(PMINI_ADAPTER Adapter, unsigned int* puiBuffer)
                        Adapter->bTriedToWakeUpFromlowPowerMode = FALSE;
 
                        wake_up(&Adapter->lowpower_mode_wait_queue);
-               #if 0
-                       if(Adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY)
-                       {
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL,"LED Thread is Running. Hence Setting the LED Event as IDLEMODE_EXIT");
-                               Adapter->DriverState = IDLEMODE_EXIT;
-                               wake_up(&Adapter->LEDInfo.notify_led_event);
-                       }
-               #endif
 
                }
                else
@@ -154,17 +146,7 @@ int InterfaceIdleModeRespond(PMINI_ADAPTER Adapter, unsigned int* puiBuffer)
        return status;
 }
 
-
-VOID InterfaceWriteIdleModeWakePattern(PMINI_ADAPTER Adapter)
-{
-/*     BeceemWriteMemoryUshort(Adapter, Host2CPU_Mailbox_Low, 0x1d1e);
-       BeceemWriteMemoryUshort(Adapter, Host2CPU_Mailbox_Low, 0x1d1e);
-       BeceemWriteMemoryUshort(Adapter, Host2CPU_Mailbox_Upp, 0xd0ea);
-       BeceemWriteMemoryUshort(Adapter, Host2CPU_Mailbox_Upp, 0xd0ea);*/
-       return;
-}
-
-int InterfaceAbortIdlemode(PMINI_ADAPTER Adapter, unsigned int Pattern)
+static int InterfaceAbortIdlemode(PMINI_ADAPTER Adapter, unsigned int Pattern)
 {
        int     status = STATUS_SUCCESS;
        unsigned int value;
index 1bc723d2d72c1ff720943f151cfafa9257bec7d8..859a2ffba6b72de17b4b69c0696bd7552212c31a 100644 (file)
@@ -7,8 +7,6 @@ INT InterfaceIdleModeRespond(PMINI_ADAPTER Adapter, unsigned int *puiBuffer);
 
 VOID InterfaceWriteIdleModeWakePattern(PMINI_ADAPTER Adapter);
 
-INT InterfaceAbortIdlemode(PMINI_ADAPTER Adapter, unsigned int Pattern);
-
 INT InterfaceWakeUp(PMINI_ADAPTER Adapter);
 
 VOID InterfaceHandleShutdownModeWakeup(PMINI_ADAPTER Adapter);
index 824f9a45007aa8aebf65852ffb172e69eae95981..8a26a3ef5bd322fdb0c63a954c05b57fae753bda 100644 (file)
@@ -2,14 +2,27 @@
 
 static struct usb_device_id InterfaceUsbtable[] = {
     { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3) },
-       { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3B) },
-       { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3L) },
-       { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_226) },
-       { USB_DEVICE(BCM_USB_VENDOR_ID_FOXCONN, BCM_USB_PRODUCT_ID_1901) },
-    {}
+    { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3B) },
+    { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3L) },
+    { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_226) },
+    { USB_DEVICE(BCM_USB_VENDOR_ID_FOXCONN, BCM_USB_PRODUCT_ID_1901) },
+
+    { }
 };
+MODULE_DEVICE_TABLE(usb, InterfaceUsbtable);
+
+static int debug = -1;
+module_param(debug, uint, 0600);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
+static const u32 default_msg =
+    NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
+    | NETIF_MSG_TIMER | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR
+    | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
+
+static INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER Adapter);
 
-VOID InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter)
+static VOID InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter)
 {
        INT i = 0;
        // Wake up the wait_queue...
@@ -48,7 +61,7 @@ VOID InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter)
        {
                if (psIntfAdapter->asUsbRcb[i].urb != NULL)
                {
-                       bcm_kfree(psIntfAdapter->asUsbRcb[i].urb->transfer_buffer);
+                       kfree(psIntfAdapter->asUsbRcb[i].urb->transfer_buffer);
                        usb_free_urb(psIntfAdapter->asUsbRcb[i].urb);
                        psIntfAdapter->asUsbRcb[i].urb = NULL;
                }
@@ -56,30 +69,7 @@ VOID InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter)
        AdapterFree(psIntfAdapter->psAdapter);
 }
 
-
-
-static int usbbcm_open(struct inode *inode, struct file *file)
-{
-       return 0;
-}
-
-static int usbbcm_release(struct inode *inode, struct file *file)
-{
-       return 0;
-}
-
-static ssize_t usbbcm_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-       return 0;
-}
-
-static ssize_t usbbcm_write(struct file *file, const char __user *user_buffer, size_t count, loff_t *ppos)
-{
-       return 0;
-}
-
-
-VOID ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter)
+static VOID ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter)
 {
        ULONG ulReg = 0;
 
@@ -157,48 +147,32 @@ VOID ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter)
 
 }
 
-static struct file_operations usbbcm_fops = {
-    .open    =  usbbcm_open,
-    .release =  usbbcm_release,
-    .read    =  usbbcm_read,
-    .write   =  usbbcm_write,
-    .owner   =  THIS_MODULE,
-       .llseek = no_llseek,
-};
-
-static struct usb_class_driver usbbcm_class = {
-    .name =            "usbbcm",
-    .fops =            &usbbcm_fops,
-    .minor_base =   BCM_USB_MINOR_BASE,
-};
-
 static int
 usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
-       int retval =0 ;
-       PMINI_ADAPTER psAdapter = NULL;
-       PS_INTERFACE_ADAPTER psIntfAdapter = NULL;
-       struct usb_device      *udev = NULL;
+       struct usb_device *udev = interface_to_usbdev (intf);
+       int retval;
+       PMINI_ADAPTER psAdapter;
+       PS_INTERFACE_ADAPTER psIntfAdapter;
+       struct net_device *ndev;
 
-//     BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Usbbcm probe!!");
-       if((intf == NULL) || (id == NULL))
-       {
-       //      BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "intf or id is NULL");
-               return -EINVAL;
-       }
-
-       /* Allocate Adapter structure */
-       if((psAdapter = kzalloc(sizeof(MINI_ADAPTER), GFP_KERNEL)) == NULL)
-       {
-               BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0, "Out of memory");
+       /* Reserve one extra queue for the bit-bucket */
+       ndev = alloc_etherdev_mq(sizeof(MINI_ADAPTER), NO_OF_QUEUES+1);
+       if(ndev == NULL) {
+               dev_err(&udev->dev, DRV_NAME ": no memory for device\n");
                return -ENOMEM;
        }
 
+       SET_NETDEV_DEV(ndev, &intf->dev);
+
+       psAdapter = netdev_priv(ndev);
+       psAdapter->dev = ndev;
+       psAdapter->msg_enable = netif_msg_init(debug, default_msg);
+
     /* Init default driver debug state */
 
-    psAdapter->stDebugState.debug_level = DBG_LVL_CURR;
+       psAdapter->stDebugState.debug_level = DBG_LVL_CURR;
        psAdapter->stDebugState.type = DBG_TYPE_INITEXIT;
-       memset (psAdapter->stDebugState.subtype, 0, sizeof (psAdapter->stDebugState.subtype));
 
     /* Technically, one can start using BCM_DEBUG_PRINT after this point.
         * However, realize that by default the Type/Subtype bitmaps are all zero now;
@@ -217,22 +191,21 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id)
        retval = InitAdapter(psAdapter);
        if(retval)
        {
-               BCM_DEBUG_PRINT (psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "InitAdapter Failed\n");
+               dev_err(&udev->dev, DRV_NAME ": InitAdapter Failed\n");
                AdapterFree(psAdapter);
                return retval;
        }
 
        /* Allocate interface adapter structure */
-       if((psAdapter->pvInterfaceAdapter =
-               kmalloc(sizeof(S_INTERFACE_ADAPTER), GFP_KERNEL)) == NULL)
+       psIntfAdapter = kzalloc(sizeof(S_INTERFACE_ADAPTER), GFP_KERNEL);
+       if (psIntfAdapter == NULL)
        {
-               BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0, "Out of memory");
+               dev_err(&udev->dev, DRV_NAME ": no memory for Interface adapter\n");
                AdapterFree (psAdapter);
                return -ENOMEM;
        }
-       memset(psAdapter->pvInterfaceAdapter, 0, sizeof(S_INTERFACE_ADAPTER));
 
-       psIntfAdapter = InterfaceAdapterGet(psAdapter);
+       psAdapter->pvInterfaceAdapter = psIntfAdapter;
        psIntfAdapter->psAdapter = psAdapter;
 
        /* Store usb interface in Interface Adapter */
@@ -255,8 +228,6 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id)
                usb_set_intfdata(intf, NULL);
                udev = interface_to_usbdev (intf);
                usb_put_dev(udev);
-               if(psAdapter->bUsbClassDriverRegistered == TRUE)
-                               usb_deregister_dev (intf, &usbbcm_class);
                InterfaceAdapterFree(psIntfAdapter);
                return retval ;
        }
@@ -269,7 +240,6 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id)
                }
        }
 
-       udev = interface_to_usbdev (intf);
        /* Check whether the USB-Device Supports remote Wake-Up */
        if(USB_CONFIG_ATT_WAKEUP & udev->actconfig->desc.bmAttributes)
        {
@@ -309,38 +279,26 @@ usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id)
 
 static void usbbcm_disconnect (struct usb_interface *intf)
 {
-       PS_INTERFACE_ADAPTER psIntfAdapter = NULL;
-       PMINI_ADAPTER psAdapter = NULL;
-       struct usb_device       *udev = NULL;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+       PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf);
+       PMINI_ADAPTER psAdapter;
+       struct usb_device  *udev = interface_to_usbdev (intf);
 
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Usb disconnected");
-       if(intf == NULL)
-       {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "intf pointer is NULL");
-               return;
-       }
-       psIntfAdapter = usb_get_intfdata(intf);
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "psIntfAdapter 0x%p",psIntfAdapter);
        if(psIntfAdapter == NULL)
-       {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "InterfaceAdapter pointer is NULL");
                return;
-       }
+
        psAdapter = psIntfAdapter->psAdapter;
+       netif_device_detach(psAdapter->dev);
+
        if(psAdapter->bDoSuspend)
                intf->needs_remote_wakeup = 0;
 
        psAdapter->device_removed = TRUE ;
        usb_set_intfdata(intf, NULL);
        InterfaceAdapterFree(psIntfAdapter);
-       udev = interface_to_usbdev (intf);
        usb_put_dev(udev);
-       usb_deregister_dev (intf, &usbbcm_class);
 }
 
-
-static __inline int AllocUsbCb(PS_INTERFACE_ADAPTER psIntfAdapter)
+static int AllocUsbCb(PS_INTERFACE_ADAPTER psIntfAdapter)
 {
        int i = 0;
        for(i = 0; i < MAXIMUM_USB_TCB; i++)
@@ -382,13 +340,11 @@ static int device_run(PS_INTERFACE_ADAPTER psIntfAdapter)
        status = InitCardAndDownloadFirmware(psIntfAdapter->psAdapter);
        if(status != STATUS_SUCCESS)
        {
-               BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "InitCardAndDownloadFirmware failed.\n");
+               pr_err(DRV_NAME "InitCardAndDownloadFirmware failed.\n");
                return status;
        }
        if(TRUE == psIntfAdapter->psAdapter->fw_download_done)
        {
-
-               BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Sending first interrupt URB down......");
                if(StartInterruptUrb(psIntfAdapter))
                {
                        BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Cannot send interrupt in URB");
@@ -401,48 +357,17 @@ static int device_run(PS_INTERFACE_ADAPTER psIntfAdapter)
                                        psIntfAdapter->psAdapter->waiting_to_fw_download_done, 5*HZ);
 
                if(value == 0)
-               {
-                       BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,"Mailbox Interrupt has not reached to Driver..");
-               }
-               else
-               {
-                       BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,"Got the mailbox interrupt ...Registering control interface...\n ");
-               }
+                       pr_err(DRV_NAME ": Mailbox Interrupt has not reached to Driver..\n");
+
                if(register_control_device_interface(psIntfAdapter->psAdapter) < 0)
                {
-                       BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Register Control Device failed...");
+                       pr_err(DRV_NAME ": Register Control Device failed...\n");
                        return -EIO;
                }
        }
        return 0;
 }
 
-#if 0
-static void    print_usb_interface_desc(struct usb_interface_descriptor *usb_intf_desc)
-{
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "**************** INTERFACE DESCRIPTOR *********************");
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bLength: %x", usb_intf_desc->bLength);
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bDescriptorType: %x", usb_intf_desc->bDescriptorType);
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bInterfaceNumber: %x", usb_intf_desc->bInterfaceNumber);
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bAlternateSetting: %x", usb_intf_desc->bAlternateSetting);
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bNumEndpoints: %x", usb_intf_desc->bNumEndpoints);
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bInterfaceClass: %x", usb_intf_desc->bInterfaceClass);
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bInterfaceSubClass: %x", usb_intf_desc->bInterfaceSubClass);
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bInterfaceProtocol: %x", usb_intf_desc->bInterfaceProtocol);
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "iInterface :%x\n",usb_intf_desc->iInterface);
-}
-static void    print_usb_endpoint_descriptor(struct usb_endpoint_descriptor *usb_ep_desc)
-{
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "**************** ENDPOINT DESCRIPTOR *********************");
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bLength  :%x ", usb_ep_desc->bLength);
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bDescriptorType  :%x ", usb_ep_desc->bDescriptorType);
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bEndpointAddress  :%x ", usb_ep_desc->bEndpointAddress);
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bmAttributes  :%x ", usb_ep_desc->bmAttributes);
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "wMaxPacketSize  :%x ",usb_ep_desc->wMaxPacketSize);
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "bInterval  :%x ",usb_ep_desc->bInterval);
-}
-
-#endif
 
 static inline int bcm_usb_endpoint_num(const struct usb_endpoint_descriptor *epd)
 {
@@ -518,7 +443,7 @@ static inline int bcm_usb_endpoint_is_isoc_out(const struct usb_endpoint_descrip
        return (bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_out(epd));
 }
 
-INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter)
+static INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter)
 {
        struct usb_host_interface *iface_desc;
        struct usb_endpoint_descriptor *endpoint;
@@ -530,20 +455,9 @@ INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter)
        UINT uiData = 0;
 
        /* Store the usb dev into interface adapter */
-       psIntfAdapter->udev = usb_get_dev(interface_to_usbdev(
-                                                               psIntfAdapter->interface));
-
-       if((psIntfAdapter->udev->speed == USB_SPEED_HIGH))
-       {
-               psIntfAdapter->bHighSpeedDevice = TRUE ;
-               BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "MODEM IS CONFIGURED TO HIGH_SPEED ");
-       }
-       else
-       {
-               psIntfAdapter->bHighSpeedDevice = FALSE ;
-               BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "MODEM IS CONFIGURED TO FULL_SPEED ");
-       }
+       psIntfAdapter->udev = usb_get_dev(interface_to_usbdev(psIntfAdapter->interface));
 
+       psIntfAdapter->bHighSpeedDevice = (psIntfAdapter->udev->speed == USB_SPEED_HIGH);
        psIntfAdapter->psAdapter->interface_rdm = BcmRDM;
        psIntfAdapter->psAdapter->interface_wrm = BcmWRM;
 
@@ -552,28 +466,27 @@ INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter)
                BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "CHIP ID Read Failed\n");
                return STATUS_FAILURE;
        }
-    if(0xbece3200==(psIntfAdapter->psAdapter->chip_id&~(0xF0)))
-       {
-               psIntfAdapter->psAdapter->chip_id=(psIntfAdapter->psAdapter->chip_id&~(0xF0));
-       }
 
-       BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "First RDM Chip ID 0x%lx\n", psIntfAdapter->psAdapter->chip_id);
+       if(0xbece3200==(psIntfAdapter->psAdapter->chip_id&~(0xF0)))
+               psIntfAdapter->psAdapter->chip_id &= ~0xF0;
 
-    iface_desc = psIntfAdapter->interface->cur_altsetting;
-       //print_usb_interface_desc(&(iface_desc->desc));
+       dev_info(&psIntfAdapter->udev->dev, "RDM Chip ID 0x%lx\n",
+                psIntfAdapter->psAdapter->chip_id);
+
+       iface_desc = psIntfAdapter->interface->cur_altsetting;
 
        if(psIntfAdapter->psAdapter->chip_id == T3B)
        {
-
                //
                //T3B device will have EEPROM,check if EEPROM is proper and BCM16 can be done or not.
                //
                BeceemEEPROMBulkRead(psIntfAdapter->psAdapter,&uiData,0x0,4);
                if(uiData == BECM)
-               {
                        bBcm16 = TRUE;
-               }
-               BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Number of Altsetting aviailable for This Modem 0x%x\n", psIntfAdapter->interface->num_altsetting);
+
+               dev_info(&psIntfAdapter->udev->dev, "number of alternate setting %d\n",
+                        psIntfAdapter->interface->num_altsetting);
+
                if(bBcm16 == TRUE)
                {
                        //selecting alternate setting one as a default setting for High Speed  modem.
@@ -644,12 +557,10 @@ INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter)
        }
 
        iface_desc = psIntfAdapter->interface->cur_altsetting;
-       //print_usb_interface_desc(&(iface_desc->desc));
-       BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Current number of endpoints :%x \n", iface_desc->desc.bNumEndpoints);
-    for (value = 0; value < iface_desc->desc.bNumEndpoints; ++value)
+
+       for (value = 0; value < iface_desc->desc.bNumEndpoints; ++value)
        {
-        endpoint = &iface_desc->endpoint[value].desc;
-               //print_usb_endpoint_descriptor(endpoint);
+               endpoint = &iface_desc->endpoint[value].desc;
 
         if (!psIntfAdapter->sBulkIn.bulk_in_endpointAddr && bcm_usb_endpoint_is_bulk_in(endpoint))
         {
@@ -682,10 +593,10 @@ INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter)
             psIntfAdapter->sIntrIn.int_in_buffer =
                                                kmalloc(buffer_size, GFP_KERNEL);
             if (!psIntfAdapter->sIntrIn.int_in_buffer) {
-                BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Could not allocate interrupt_in_buffer");
+                   dev_err(&psIntfAdapter->udev->dev,
+                           "could not allocate interrupt_in_buffer\n");
                 return -EINVAL;
             }
-                       //psIntfAdapter->sIntrIn.int_in_pipe =
         }
 
         if (!psIntfAdapter->sIntrOut.int_out_endpointAddr && bcm_usb_endpoint_is_int_out(endpoint))
@@ -716,26 +627,15 @@ INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter)
                    psIntfAdapter->sIntrOut.int_out_buffer= kmalloc(buffer_size,
                                                                                                                GFP_KERNEL);
                        if (!psIntfAdapter->sIntrOut.int_out_buffer)
-                                       {
-                       BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Could not allocate interrupt_out_buffer");
-                       return -EINVAL;
-            }
+                       {
+                               dev_err(&psIntfAdapter->udev->dev,
+                                       "could not allocate interrupt_out_buffer\n");
+                                       return -EINVAL;
+                       }
         }
     }
        }
     usb_set_intfdata(psIntfAdapter->interface, psIntfAdapter);
-    retval = usb_register_dev(psIntfAdapter->interface, &usbbcm_class);
-       if(retval)
-       {
-               BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "usb register dev failed = %d", retval);
-               psIntfAdapter->psAdapter->bUsbClassDriverRegistered = FALSE;
-               return retval;
-       }
-       else
-       {
-               psIntfAdapter->psAdapter->bUsbClassDriverRegistered = TRUE;
-               BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "usb dev registered");
-       }
 
        psIntfAdapter->psAdapter->bcm_file_download = InterfaceFileDownload;
        psIntfAdapter->psAdapter->bcm_file_readback_from_chip =
@@ -757,21 +657,13 @@ INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter)
        }
 
 
-       retval = device_run(psIntfAdapter);
-       if(retval)
-       {
-               return retval;
-       }
-
-
-       return 0;
+       return device_run(psIntfAdapter);
 }
 
 static int InterfaceSuspend (struct usb_interface *intf, pm_message_t message)
 {
        PS_INTERFACE_ADAPTER  psIntfAdapter = usb_get_intfdata(intf);
-       BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "=================================\n");
-       //Bcm_kill_all_URBs(psIntfAdapter);
+
        psIntfAdapter->bSuspended = TRUE;
 
        if(TRUE == psIntfAdapter->bPreparingForBusSuspend)
@@ -812,57 +704,43 @@ static int InterfaceResume (struct usb_interface *intf)
        return 0;
 }
 
-static int InterfacePreReset(struct usb_interface *intf)
-{
-    printk("====================>");
-       return STATUS_SUCCESS;
-}
-
-static int InterfacePostReset(struct usb_interface *intf)
-{
-    printk("Do Post chip reset setting here if it is required");
-       return STATUS_SUCCESS;
-}
 static struct usb_driver usbbcm_driver = {
     .name = "usbbcm",
     .probe = usbbcm_device_probe,
     .disconnect = usbbcm_disconnect,
     .suspend = InterfaceSuspend,
     .resume = InterfaceResume,
-       .pre_reset=InterfacePreReset,
-       .post_reset=InterfacePostReset,
     .id_table = InterfaceUsbtable,
     .supports_autosuspend = 1,
 };
 
+struct class *bcm_class;
 
-/*
-Function:                              InterfaceInitialize
 
-Description:                   This is the hardware specific initialization Function.
-                                               Registering the driver with NDIS , other device specific NDIS
-                                               and hardware initializations are done here.
-
-Input parameters:              IN PMINI_ADAPTER Adapter   - Miniport Adapter Context
+static __init int bcm_init(void)
+{
+       printk(KERN_INFO "%s: %s, %s\n", DRV_NAME, DRV_DESCRIPTION, DRV_VERSION);
+       printk(KERN_INFO "%s\n", DRV_COPYRIGHT);
 
+       bcm_class = class_create(THIS_MODULE, DRV_NAME);
+       if (IS_ERR(bcm_class)) {
+               printk(KERN_ERR DRV_NAME ": could not create class\n");
+               return PTR_ERR(bcm_class);
+       }
 
-Return:                                        BCM_STATUS_SUCCESS - If Initialization of the
-                                               HW Interface was successful.
-                                               Other           - If an error occured.
-*/
-INT InterfaceInitialize(void)
-{
-//     BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Registering Usb driver!!");
        return usb_register(&usbbcm_driver);
 }
 
-INT InterfaceExit(void)
+static __exit void bcm_exit(void)
 {
-       //PMINI_ADAPTER psAdapter = NULL;
-       int status = 0;
+        class_destroy (bcm_class);
 
-       //BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Deregistering Usb driver!!");
        usb_deregister(&usbbcm_driver);
-       return status;
 }
+
+module_init(bcm_init);
+module_exit(bcm_exit);
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
 MODULE_LICENSE ("GPL");
index e7a96e5c5c505406d68b8e129f75a945995ad1bf..3b8e17b619ba3032f707d76b83ed2eddd4640e23 100644 (file)
@@ -19,33 +19,7 @@ INT InterfaceInitialize(void);
 
 INT InterfaceExit(void);
 
-#ifndef BCM_SHM_INTERFACE
-INT InterfaceAdapterInit(PS_INTERFACE_ADAPTER Adapter);
-
 INT usbbcm_worker_thread(PS_INTERFACE_ADAPTER psIntfAdapter);
 
-VOID InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter);
-
-#else
-INT InterfaceAdapterInit(PMINI_ADAPTER Adapter);
-#endif
-
-
-#if 0
-
-ULONG InterfaceClaimAdapter(PMINI_ADAPTER Adapter);
-
-VOID InterfaceDDRControllerInit(PMINI_ADAPTER Adapter);
-
-ULONG InterfaceReset(PMINI_ADAPTER Adapter);
-
-ULONG InterfaceRegisterResources(PMINI_ADAPTER Adapter);
-
-VOID InterfaceUnRegisterResources(PMINI_ADAPTER Adapter);
-
-ULONG InterfaceFirmwareDownload(PMINI_ADAPTER Adapter);
-
-#endif
-
 #endif
 
index f928fe4d564d4a95075021a1e16de50ff16bed25..423464765e5949d171ad4c17ea9cb4d777e866dc 100644 (file)
@@ -1,6 +1,5 @@
 #include "headers.h"
 
-#ifndef BCM_SHM_INTERFACE
 
 static void read_int_callback(struct urb *urb/*, struct pt_regs *regs*/)
 {
@@ -8,6 +7,10 @@ static void read_int_callback(struct urb *urb/*, struct pt_regs *regs*/)
        PS_INTERFACE_ADAPTER psIntfAdapter = (PS_INTERFACE_ADAPTER)urb->context;
        PMINI_ADAPTER Adapter = psIntfAdapter->psAdapter ;
 
+       if (netif_msg_intr(Adapter))
+               pr_info(PFX "%s: interrupt status %d\n",
+                       Adapter->dev->name, status);
+
        if(Adapter->device_removed == TRUE)
        {
                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL,"Device has Got Removed.");
@@ -164,40 +167,3 @@ INT StartInterruptUrb(PS_INTERFACE_ADAPTER psIntfAdapter)
        return status;
 }
 
-/*
-Function:                              InterfaceEnableInterrupt
-
-Description:                   This is the hardware specific Function for configuring
-                                               and enabling the interrupts on the device.
-
-Input parameters:              IN PMINI_ADAPTER Adapter   - Miniport Adapter Context
-
-
-Return:                                BCM_STATUS_SUCCESS - If configuring the interrupts was successful.
-                                               Other           - If an error occured.
-*/
-
-void InterfaceEnableInterrupt(PMINI_ADAPTER Adapter)
-{
-
-}
-
-/*
-Function:                              InterfaceDisableInterrupt
-
-Description:                   This is the hardware specific Function for disabling the interrupts on the device.
-
-Input parameters:              IN PMINI_ADAPTER Adapter   - Miniport Adapter Context
-
-
-Return:                                BCM_STATUS_SUCCESS - If disabling the interrupts was successful.
-                                               Other           - If an error occured.
-*/
-
-void InterfaceDisableInterrupt(PMINI_ADAPTER Adapter)
-{
-
-}
-
-#endif
-
index 8fc893b37fe403b9f50a47efe59a77b01484c6c1..b7d6e7a414a98d5ff7cc514e5753a11ac5bce632 100644 (file)
@@ -1,17 +1,5 @@
 #include "headers.h"
 
-#ifndef BCM_SHM_INTERFACE
-
-PS_INTERFACE_ADAPTER
-InterfaceAdapterGet(PMINI_ADAPTER psAdapter)
-{
-       if(psAdapter == NULL)
-       {
-               return NULL;
-       }
-       return (PS_INTERFACE_ADAPTER)(psAdapter->pvInterfaceAdapter);
-}
-
 INT
 InterfaceRDM(PS_INTERFACE_ADAPTER psIntfAdapter,
             UINT addr,
@@ -236,9 +224,7 @@ VOID Bcm_kill_all_URBs(PS_INTERFACE_ADAPTER psIntfAdapter)
        }
 
        /* Cancel All submitted TX URB's */
-       BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Cancelling All Submitted TX Urbs \n");
-
-    for(i = 0; i < MAXIMUM_USB_TCB; i++)
+       for(i = 0; i < MAXIMUM_USB_TCB; i++)
        {
                tempUrb = psIntfAdapter->asUsbTcb[i].urb;
                if(tempUrb)
@@ -248,9 +234,6 @@ VOID Bcm_kill_all_URBs(PS_INTERFACE_ADAPTER psIntfAdapter)
                }
        }
 
-
-    BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "Cancelling All submitted Rx Urbs \n");
-
        for(i = 0; i < MAXIMUM_USB_RCB; i++)
        {
                tempUrb = psIntfAdapter->asUsbRcb[i].urb;
@@ -261,16 +244,11 @@ VOID Bcm_kill_all_URBs(PS_INTERFACE_ADAPTER psIntfAdapter)
                }
        }
 
-
        atomic_set(&psIntfAdapter->uNumTcbUsed, 0);
        atomic_set(&psIntfAdapter->uCurrTcb, 0);
 
        atomic_set(&psIntfAdapter->uNumRcbUsed, 0);
        atomic_set(&psIntfAdapter->uCurrRcb, 0);
-
-       BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "TCB: used- %d cur-%d\n", atomic_read(&psIntfAdapter->uNumTcbUsed), atomic_read(&psIntfAdapter->uCurrTcb));
-       BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_PRINTK, 0, 0, "RCB: used- %d cur-%d\n", atomic_read(&psIntfAdapter->uNumRcbUsed), atomic_read(&psIntfAdapter->uCurrRcb));
-
 }
 
 VOID putUsbSuspend(struct work_struct *work)
@@ -282,9 +260,6 @@ VOID putUsbSuspend(struct work_struct *work)
 
        if(psIntfAdapter->bSuspended == FALSE)
                usb_autopm_put_interface(intf);
-       else
-               BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Interface Resumed Completely\n");
 
 }
 
-#endif
index 74c81d45cff48bdab97f984d83515ef548caf2fa..6c9e39bf9889bb6ba042b58498b6cb614255e5e0 100644 (file)
@@ -1,9 +1,6 @@
 #ifndef __INTERFACE_MISC_H
 #define __INTERFACE_MISC_H
 
-PS_INTERFACE_ADAPTER
-InterfaceAdapterGet(PMINI_ADAPTER psAdapter);
-
 INT
 InterfaceRDM(PS_INTERFACE_ADAPTER psIntfAdapter,
                        UINT addr,
index 6fee9684f2efd7805aa0aa94635ad76e8fd6f2b8..533f8ebe0f8426ff528f2ef6f1596db1b40ac494 100644 (file)
@@ -1,5 +1,15 @@
 #include "headers.h"
-extern int SearchVcid(PMINI_ADAPTER , unsigned short);
+
+static int SearchVcid(PMINI_ADAPTER Adapter,unsigned short usVcid)
+{
+       int iIndex=0;
+
+       for(iIndex=(NO_OF_QUEUES-1);iIndex>=0;iIndex--)
+               if(Adapter->PackInfo[iIndex].usVCID_Value == usVcid)
+                       return iIndex;
+       return NO_OF_QUEUES+1;
+
+}
 
 
 static PUSB_RCB
@@ -38,13 +48,9 @@ static void read_bulk_callback(struct urb *urb)
        PMINI_ADAPTER Adapter = psIntfAdapter->psAdapter;
        PLEADER pLeader = urb->transfer_buffer;
 
-
-       #if 0
-       int *puiBuffer = NULL;
-       struct timeval tv;
-       memset(&tv, 0, sizeof(tv));
-       do_gettimeofday(&tv);
-       #endif
+       if (unlikely(netif_msg_rx_status(Adapter)))
+               pr_info(PFX "%s: rx urb status %d length %d\n",
+                       Adapter->dev->name, urb->status, urb->actual_length);
 
        if((Adapter->device_removed == TRUE)  ||
                (TRUE == Adapter->bEndPointHalted) ||
@@ -89,10 +95,10 @@ static void read_bulk_callback(struct urb *urb)
        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Leader Status:0x%hX, Length:0x%hX, VCID:0x%hX", pLeader->Status,pLeader->PLength,pLeader->Vcid);
        if(MAX_CNTL_PKT_SIZE < pLeader->PLength)
        {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Corrupted leader length...%d\n",
-                                       pLeader->PLength);
-               atomic_inc(&Adapter->RxPacketDroppedCount);
-               atomic_add(pLeader->PLength, &Adapter->BadRxByteCount);
+               if (netif_msg_rx_err(Adapter))
+                       pr_info(PFX "%s: corrupted leader length...%d\n",
+                               Adapter->dev->name, pLeader->PLength);
+               ++Adapter->dev->stats.rx_dropped;
                atomic_dec(&psIntfAdapter->uNumRcbUsed);
                return;
        }
@@ -145,10 +151,9 @@ static void read_bulk_callback(struct urb *urb)
                skb_put (skb, pLeader->PLength + ETH_HLEN);
                Adapter->PackInfo[QueueIndex].uiTotalRxBytes+=pLeader->PLength;
                Adapter->PackInfo[QueueIndex].uiThisPeriodRxBytes+= pLeader->PLength;
-               atomic_add(pLeader->PLength, &Adapter->GoodRxByteCount);
         BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "Recived Data pkt of len :0x%X", pLeader->PLength);
 
-               if(Adapter->if_up)
+               if(netif_running(Adapter->dev))
                {
                        /* Moving ahead by ETH_HLEN to the data ptr as received from FW */
                        skb_pull(skb, ETH_HLEN);
@@ -173,9 +178,12 @@ static void read_bulk_callback(struct urb *urb)
                else
                {
                    BCM_DEBUG_PRINT(psIntfAdapter->psAdapter,DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "i/f not up hance freeing SKB...");
-                       bcm_kfree_skb(skb);
+                       dev_kfree_skb(skb);
                }
-               atomic_inc(&Adapter->GoodRxPktCount);
+
+               ++Adapter->dev->stats.rx_packets;
+               Adapter->dev->stats.rx_bytes += pLeader->PLength;
+
                for(uiIndex = 0 ; uiIndex < MIBS_MAX_HIST_ENTRIES ; uiIndex++)
                {
                        if((pLeader->PLength <= MIBS_PKTSIZEHIST_RANGE*(uiIndex+1))
index 771f7b34d2ec4a9306bc03e5252863eb536c91dd..f434b899a0d02ecddadaf66ba961107df912e747 100644 (file)
@@ -1,50 +1,5 @@
 #include "headers.h"
 
-#ifndef BCM_SHM_INTERFACE
-
-/*
-Function:                              InterfaceTxDataPacket
-
-Description:                   This is the hardware specific Function for Transmitting
-                                               data packet to the device.
-
-Input parameters:              IN PMINI_ADAPTER Adapter   - Miniport Adapter Context
-                                               PVOID Packet                            -  Packet Containing the data to be transmitted
-                                               USHORT usVcid                      - VCID on which data packet is to be sent
-
-
-Return:                                BCM_STATUS_SUCCESS - If Tx was successful.
-                                               Other           - If an error occured.
-*/
-
-ULONG InterfaceTxDataPacket(PMINI_ADAPTER Adapter,PVOID Packet,USHORT usVcid)
-{
-       ULONG   Status = 0;
-       return Status;
-}
-
-/*
-Function:                              InterfaceTxControlPacket
-
-Description:                   This is the hardware specific Function for Transmitting
-                                               control packet to the device.
-
-Input parameters:              IN PMINI_ADAPTER Adapter   - Miniport Adapter Context
-                                               PVOID pvBuffer                     - Buffer containg control packet
-                                               UINT uiBufferLength                - Buffer Length
-
-Return:                                BCM_STATUS_SUCCESS - If control packet transmit was successful.
-                                               Other           - If an error occured.
-*/
-
-ULONG InterfaceTxControlPacket(PMINI_ADAPTER Adapter,PVOID pvBuffer,UINT uiBufferLength)
-{
-       ULONG   Status = 0;
-
-
-
-       return Status;
-}
 /*this is transmit call-back(BULK OUT)*/
 static void write_bulk_callback(struct urb *urb/*, struct pt_regs *regs*/)
 {
@@ -54,10 +9,10 @@ static void write_bulk_callback(struct urb *urb/*, struct pt_regs *regs*/)
        PMINI_ADAPTER psAdapter = psIntfAdapter->psAdapter ;
        BOOLEAN bpowerDownMsg = FALSE ;
     PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
-#if 0
-       struct timeval tv;
-       UINT time_ms = 0;
-#endif
+
+    if (unlikely(netif_msg_tx_done(Adapter)))
+           pr_info(PFX "%s: transmit status %d\n", Adapter->dev->name, urb->status);
+
        if(urb->status != STATUS_SUCCESS)
        {
                if(urb->status == -EPIPE)
@@ -78,11 +33,6 @@ static void write_bulk_callback(struct urb *urb/*, struct pt_regs *regs*/)
 
        if(TRUE == psAdapter->bPreparingForLowPowerMode)
        {
-               #if 0
-               do_gettimeofday(&tv);
-               time_ms = tv.tv_sec *1000 + tv.tv_usec/1000;
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, " %s Idle Mode ACK_Sent got from device at time :0x%x", __FUNCTION__, time_ms);
-               #endif
 
                if(((pControlMsg->szData[0] == GO_TO_IDLE_MODE_PAYLOAD) &&
                        (pControlMsg->szData[1] == TARGET_CAN_GO_TO_IDLE_MODE)))
@@ -162,7 +112,7 @@ err_exit :
 }
 
 
-static __inline PUSB_TCB GetBulkOutTcb(PS_INTERFACE_ADAPTER psIntfAdapter)
+static PUSB_TCB GetBulkOutTcb(PS_INTERFACE_ADAPTER psIntfAdapter)
 {
        PUSB_TCB pTcb = NULL;
        UINT index = 0;
@@ -183,7 +133,7 @@ static __inline PUSB_TCB GetBulkOutTcb(PS_INTERFACE_ADAPTER psIntfAdapter)
        return pTcb;
 }
 
-static __inline int TransmitTcb(PS_INTERFACE_ADAPTER psIntfAdapter, PUSB_TCB pTcb, PVOID data, int len)
+static int TransmitTcb(PS_INTERFACE_ADAPTER psIntfAdapter, PUSB_TCB pTcb, PVOID data, int len)
 {
 
        struct urb *urb = pTcb->urb;
@@ -255,5 +205,4 @@ int InterfaceTransmitPacket(PVOID arg, PVOID data, UINT len)
        return TransmitTcb(psIntfAdapter, pTcb, data, len);
 }
 
-#endif
 
index 053f631e204243ca8dea4bba89dd74648a6b4a6b..273147577c17d9ccef8b8f5d6f90f0c1d3297bdf 100644 (file)
@@ -3,11 +3,5 @@
 
 INT InterfaceTransmitPacket(PVOID arg, PVOID data, UINT len);
 
-
-ULONG InterfaceTxDataPacket(PMINI_ADAPTER Adapter,PVOID Packet,USHORT usVcid);
-
-ULONG InterfaceTxControlPacket(PMINI_ADAPTER Adapter,PVOID pvBuffer,UINT uiBufferLength);
-
-
 #endif
 
diff --git a/drivers/staging/bcm/Interfacemain.h b/drivers/staging/bcm/Interfacemain.h
deleted file mode 100644 (file)
index e0db563..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _MAIN_
-#define _MAIN_
-#if 0
-typedef struct _MINI_ADAPTER
-{
-       S_INTERFACE_ADAPTER stInterfaceAdapter;
-}MINI_ADAPTER,*PMINI_ADAPTER;
-
-#endif
-#endif
index cae382313ce91d78b22e54d18382b97a5ad25a47..f4cf41c0e46bbc51e019338c37e170bfb35d7965 100644 (file)
@@ -75,14 +75,14 @@ static VOID UpdateTokenCount(register PMINI_ADAPTER Adapter)
 * Returns     - The number of bytes allowed for transmission.
 *
 ***********************************************************************/
-static __inline ULONG GetSFTokenCount(PMINI_ADAPTER Adapter, PacketInfo *psSF)
+static ULONG GetSFTokenCount(PMINI_ADAPTER Adapter, PacketInfo *psSF)
 {
        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IsPacketAllowedForFlow ===>");
        /* Validate the parameters */
        if(NULL == Adapter || (psSF < Adapter->PackInfo &&
                (uintptr_t)psSF > (uintptr_t) &Adapter->PackInfo[HiPriority]))
        {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Got wrong Parameters:Adapter: %p, QIndex: %ld\n", Adapter, (psSF-Adapter->PackInfo));
+               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Got wrong Parameters:Adapter: %p, QIndex: %zd\n", Adapter, (psSF-Adapter->PackInfo));
                return 0;
        }
 
@@ -94,51 +94,27 @@ static __inline ULONG GetSFTokenCount(PMINI_ADAPTER Adapter, PacketInfo *psSF)
                }
                else
                {
-                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "Not enough tokens in queue %ld Available %u\n",
+                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "Not enough tokens in queue %zd Available %u\n",
                                psSF-Adapter->PackInfo, psSF->uiCurrentTokenCount);
                        psSF->uiPendedLast = 1;
                }
        }
        else
        {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Queue %ld not valid\n", psSF-Adapter->PackInfo);
+               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Queue %zd not valid\n", psSF-Adapter->PackInfo);
        }
        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IsPacketAllowedForFlow <===");
        return 0;
 }
 
-static __inline void RemovePacketFromQueue(PacketInfo *pPackInfo , struct sk_buff *Packet)
-{
-       struct sk_buff *psQueueCurrent=NULL, *psLastQueueNode=NULL;
-       psQueueCurrent = pPackInfo->FirstTxQueue;
-       while(psQueueCurrent)
-       {
-               if(Packet == psQueueCurrent)
-               {
-                       if(psQueueCurrent == pPackInfo->FirstTxQueue)
-                       {
-                               pPackInfo->FirstTxQueue=psQueueCurrent->next;
-                               if(psQueueCurrent==pPackInfo->LastTxQueue)
-                                       pPackInfo->LastTxQueue=NULL;
-                       }
-                       else
-                       {
-                               psLastQueueNode->next=psQueueCurrent->next;
-                       }
-                       break;
-               }
-               psLastQueueNode = psQueueCurrent;
-               psQueueCurrent=psQueueCurrent->next;
-       }
-}
 /**
 @ingroup tx_functions
 This function despatches packet from the specified queue.
 @return Zero(success) or Negative value(failure)
 */
-static __inline INT SendPacketFromQueue(PMINI_ADAPTER Adapter,/**<Logical Adapter*/
-                                                               PacketInfo *psSF,               /**<Queue identifier*/
-                                                               struct sk_buff*  Packet)        /**<Pointer to the packet to be sent*/
+static INT SendPacketFromQueue(PMINI_ADAPTER Adapter,/**<Logical Adapter*/
+                              PacketInfo *psSF,                /**<Queue identifier*/
+                              struct sk_buff*  Packet) /**<Pointer to the packet to be sent*/
 {
        INT     Status=STATUS_FAILURE;
        UINT uiIndex =0,PktLen = 0;
@@ -180,8 +156,7 @@ static __inline INT SendPacketFromQueue(PMINI_ADAPTER Adapter,/**<Logical Adapte
 * Returns     - None.
 *
 ****************************************************************************/
-static __inline VOID CheckAndSendPacketFromIndex
-(PMINI_ADAPTER Adapter, PacketInfo *psSF)
+static VOID CheckAndSendPacketFromIndex(PMINI_ADAPTER Adapter, PacketInfo *psSF)
 {
        struct sk_buff  *QueuePacket=NULL;
        char                    *pControlPacket = NULL;
@@ -189,7 +164,7 @@ static __inline VOID CheckAndSendPacketFromIndex
        int                             iPacketLen=0;
 
 
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "%ld ====>", (psSF-Adapter->PackInfo));
+       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "%zd ====>", (psSF-Adapter->PackInfo));
        if((psSF != &Adapter->PackInfo[HiPriority]) && Adapter->LinkUpStatus && atomic_read(&psSF->uiPerSFTxResourceCount))//Get data packet
        {
                if(!psSF->ucDirection )
@@ -197,10 +172,8 @@ static __inline VOID CheckAndSendPacketFromIndex
 
                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "UpdateTokenCount ");
                if(Adapter->IdleMode || Adapter->bPreparingForLowPowerMode)
-               {
-                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Device is in Idle Mode..Hence blocking Data Packets..\n");
-                       return;
-               }
+                       return; /* in idle mode */
+
                // Check for Free Descriptors
                if(atomic_read(&Adapter->CurrNumFreeTxDesc) <= MINIMUM_PENDING_DESCRIPTORS)
                {
@@ -208,9 +181,6 @@ static __inline VOID CheckAndSendPacketFromIndex
                        return ;
                }
 
-#if 0
-               PruneQueue(Adapter,(psSF-Adapter->PackInfo));
-#endif
                spin_lock_bh(&psSF->SFQueueLock);
                QueuePacket=psSF->FirstTxQueue;
 
@@ -240,7 +210,7 @@ static __inline VOID CheckAndSendPacketFromIndex
                        }
                        else
                        {
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "For Queue: %ld\n", psSF-Adapter->PackInfo);
+                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "For Queue: %zd\n", psSF-Adapter->PackInfo);
                                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nAvailable Tokens = %d required = %d\n",
                                        psSF->uiCurrentTokenCount, iPacketLen);
                                //this part indicates that becuase of non-availability of the tokens
@@ -290,17 +260,6 @@ static __inline VOID CheckAndSendPacketFromIndex
                        }
                }
        }
-
-       if(Status != STATUS_SUCCESS)    //Tx of data packet to device Failed
-       {
-               if(Adapter->bcm_jiffies == 0)
-                       Adapter->bcm_jiffies = jiffies;
-       }
-       else
-       {
-               Adapter->bcm_jiffies = 0;
-       }
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "<=====");
 }
 
 
@@ -387,12 +346,7 @@ VOID transmit_packets(PMINI_ADAPTER Adapter)
                if(exit_flag == TRUE )
                    break ;
        }/* end of inner while loop */
-       if(Adapter->bcm_jiffies == 0 &&
-               atomic_read(&Adapter->TotalPacketCount) != 0 &&
-               uiPrevTotalCount == atomic_read(&Adapter->TotalPacketCount))
-       {
-               Adapter->bcm_jiffies = jiffies;
-       }
+
        update_per_cid_rx  (Adapter);
        Adapter->txtransmit_running = 0;
        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "<======");
index 0241234605f156774d605add63e303a48732747a..feb351578c8bd147c13e04bb06263426c9590ca4 100644 (file)
@@ -4,10 +4,6 @@
 #ifndef        __MACROS_H__
 #define __MACROS_H__
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
-#define kthread_run(threadfn,data,datafmt)(struct task_struct *)kernel_thread(threadfn,data,0)
-#endif
-
 #define TX_TIMER_PERIOD 10     //10 msec
 #define MAX_CLASSIFIERS 100
 //#define MAX_CLASSIFIERS_PER_SF  20
 #define MAX_DATA_PKTS          200
 #define MAX_ETH_SIZE           1536
 #define MAX_CNTL_PKT_SIZE 2048
-/* TIMER RELATED */
-#define JIFFIES_2_QUADPART()   (ULONG)(jiffies * 10000) // jiffies(1msec) to Quadpart(100nsec)
 
 #define MTU_SIZE 1400
+#define TX_QLEN  5
 
 #define MAC_ADDR_REGISTER 0xbf60d000
 
@@ -266,7 +261,7 @@ typedef enum _E_PHS_DSC_ACTION
 
 #define FIRMWARE_BEGIN_ADDR 0xBFC00000
 
-#define INVALID_QUEUE_INDEX (USHORT)-1
+#define INVALID_QUEUE_INDEX NO_OF_QUEUES
 
 #define INVALID_PID (pid_t)-1
 #define DDR_80_MHZ     0
@@ -300,12 +295,7 @@ typedef enum _E_PHS_DSC_ACTION
 
 /* Idle Mode Related Registers */
 #define DEBUG_INTERRUPT_GENERATOR_REGISTOR 0x0F00007C
-#ifdef BCM_SHM_INTERFACE
-#define SW_ABORT_IDLEMODE_LOC          0xbfc02f9c
-#define CPE_VIRTUAL_MAILBOX_REG     0xBFC02E58
-#else
 #define SW_ABORT_IDLEMODE_LOC          0x0FF01FFC
-#endif
 
 #define SW_ABORT_IDLEMODE_PATTERN      0xd0ea1d1e
 #define DEVICE_INT_OUT_EP_REG0         0x0F011870
@@ -355,12 +345,7 @@ typedef enum ePMU_MODES
        HYBRID_MODE_6   = 2
 }PMU_MODE;
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
-#define MAX_RDM_WRM_RETIRES 16
-#else
 #define MAX_RDM_WRM_RETIRES 1
-#endif
-
 
 enum eAbortPattern {
        ABORT_SHUTDOWN_MODE = 1,
@@ -369,27 +354,6 @@ enum eAbortPattern {
        ABORT_IDLE_SYNCDOWN = 3
 };
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
-       #define GET_BCM_ADAPTER(net_dev)  ({\
-    PMINI_ADAPTER __Adapter = NULL;    \
-    if (net_dev)    {   \
-         __Adapter = (PMINI_ADAPTER)(net_dev->priv); \
-    } \
-    else    {   \
-         __Adapter = NULL;  \
-    }__Adapter;} )
-#else
-       #define GET_BCM_ADAPTER(net_dev) ({\
-    PMINI_ADAPTER __Adapter = NULL;    \
-    if (net_dev)    {   \
-         __Adapter = (PMINI_ADAPTER)(*((unsigned long *)netdev_priv(net_dev)));  \
-    } \
-    else    {   \
-         __Adapter = NULL;  \
-    }__Adapter;})
-
-
-#endif
 
 /* Offsets used by driver in skb cb variable */
 #define SKB_CB_CLASSIFICATION_OFFSET    0
index c3ae25af670aef451cb63fae574f6b7184b0299b..652b7f87737cd0ba46a61826c29d4daf71a870bd 100644 (file)
@@ -6,7 +6,7 @@ obj-$(CONFIG_BCM_WIMAX) +=      bcm_wimax.o
 
 bcm_wimax-y :=  InterfaceDld.o InterfaceIdleMode.o InterfaceInit.o InterfaceRx.o \
                InterfaceIsr.o InterfaceMisc.o InterfaceTx.o \
-               Arp.o CmHost.o Debug.o IPv6Protocol.o Qos.o Transmit.o\
+               CmHost.o IPv6Protocol.o Qos.o Transmit.o\
                Bcmnet.o DDRInit.o HandleControlPacket.o\
                LeakyBucket.o Misc.o sort.o Bcmchar.o hostmibs.o PHSModule.o\
-               Osal_Misc.o led_control.o nvm.o vendorspecificextn.o
+               led_control.o nvm.o vendorspecificextn.o
index 22550f745917cb777c85eb1c8897b47d13bcb015..82d9f86821ca2b940c447744664f2af4e30db047 100644 (file)
@@ -1,5 +1,12 @@
 #include "headers.h"
 
+static int BcmFileDownload(PMINI_ADAPTER Adapter, const char *path,
+                        unsigned int loc);
+static VOID doPowerAutoCorrection(PMINI_ADAPTER psAdapter);
+static void HandleShutDownModeRequest(PMINI_ADAPTER Adapter,PUCHAR pucBuffer);
+static int bcm_parse_target_params(PMINI_ADAPTER Adapter);
+static void beceem_protocol_reset (PMINI_ADAPTER Adapter);
+
 static VOID default_wimax_protocol_initialize(PMINI_ADAPTER Adapter)
 {
 
@@ -60,15 +67,6 @@ InitAdapter(PMINI_ADAPTER psAdapter)
     //init_waitqueue_head(&psAdapter->device_wake_queue);
     psAdapter->fw_download_done=FALSE;
 
-    psAdapter->pvOsDepData = (PLINUX_DEP_DATA) kmalloc(sizeof(LINUX_DEP_DATA),
-                 GFP_KERNEL);
-
-    if(psAdapter->pvOsDepData == NULL)
-       {
-        BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Linux Specific Data allocation failed");
-        return -ENOMEM;
-    }
-    memset(psAdapter->pvOsDepData, 0, sizeof(LINUX_DEP_DATA));
 
        default_wimax_protocol_initialize(psAdapter);
        for (i=0;i<MAX_CNTRL_PKTS;i++)
@@ -117,7 +115,7 @@ InitAdapter(PMINI_ADAPTER psAdapter)
 
 VOID AdapterFree(PMINI_ADAPTER Adapter)
 {
-       INT count = 0;
+       int count;
 
        beceem_protocol_reset(Adapter);
 
@@ -125,72 +123,66 @@ VOID AdapterFree(PMINI_ADAPTER Adapter)
 
        if(Adapter->control_packet_handler && !IS_ERR(Adapter->control_packet_handler))
                kthread_stop (Adapter->control_packet_handler);
+
        if(Adapter->transmit_packet_thread && !IS_ERR(Adapter->transmit_packet_thread))
-       kthread_stop (Adapter->transmit_packet_thread);
-    wake_up(&Adapter->process_read_wait_queue);
+               kthread_stop (Adapter->transmit_packet_thread);
+
+       wake_up(&Adapter->process_read_wait_queue);
+
        if(Adapter->LEDInfo.led_thread_running & (BCM_LED_THREAD_RUNNING_ACTIVELY | BCM_LED_THREAD_RUNNING_INACTIVELY))
                kthread_stop (Adapter->LEDInfo.led_cntrl_threadid);
-       bcm_unregister_networkdev(Adapter);
+
+       unregister_networkdev(Adapter);
+
+       /* FIXME: use proper wait_event and refcounting */
        while(atomic_read(&Adapter->ApplicationRunning))
        {
                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Waiting for Application to close.. %d\n",atomic_read(&Adapter->ApplicationRunning));
                msleep(100);
        }
        unregister_control_device_interface(Adapter);
-       if(Adapter->dev && !IS_ERR(Adapter->dev))
-               free_netdev(Adapter->dev);
-       if(Adapter->pstargetparams != NULL)
-       {
-               bcm_kfree(Adapter->pstargetparams);
-       }
+
+       kfree(Adapter->pstargetparams);
+
        for (count =0;count < MAX_CNTRL_PKTS;count++)
-       {
-               if(Adapter->txctlpacket[count])
-                       bcm_kfree(Adapter->txctlpacket[count]);
-       }
+               kfree(Adapter->txctlpacket[count]);
+
        FreeAdapterDsxBuffer(Adapter);
-       if(Adapter->pvOsDepData)
-               bcm_kfree (Adapter->pvOsDepData);
-       if(Adapter->pvInterfaceAdapter)
-               bcm_kfree(Adapter->pvInterfaceAdapter);
+
+       kfree(Adapter->pvInterfaceAdapter);
 
        //Free the PHS Interface
        PhsCleanup(&Adapter->stBCMPhsContext);
 
-#ifndef BCM_SHM_INTERFACE
        BcmDeAllocFlashCSStructure(Adapter);
-#endif
 
-       bcm_kfree (Adapter);
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "<========\n");
+       free_netdev(Adapter->dev);
 }
 
-
-int create_worker_threads(PMINI_ADAPTER psAdapter)
+static int create_worker_threads(PMINI_ADAPTER psAdapter)
 {
-       BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Init Threads...");
        // Rx Control Packets Processing
        psAdapter->control_packet_handler = kthread_run((int (*)(void *))
-                       control_packet_handler, psAdapter, "CtrlPktHdlr");
+                                                       control_packet_handler, psAdapter, "%s-rx", DRV_NAME);
        if(IS_ERR(psAdapter->control_packet_handler))
        {
-               BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "No Kernel Thread, but still returning success\n");
+               pr_notice(DRV_NAME ": could not create control thread\n");
                return PTR_ERR(psAdapter->control_packet_handler);
        }
+
        // Tx Thread
        psAdapter->transmit_packet_thread = kthread_run((int (*)(void *))
-               tx_pkt_handler, psAdapter, "TxPktThread");
+                                                       tx_pkt_handler, psAdapter, "%s-tx", DRV_NAME);
        if(IS_ERR (psAdapter->transmit_packet_thread))
        {
-               BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "No Kernel Thread, but still returning success");
+               pr_notice(DRV_NAME ": could not creat transmit thread\n");
                kthread_stop(psAdapter->control_packet_handler);
                return PTR_ERR(psAdapter->transmit_packet_thread);
        }
        return 0;
 }
 
-
-static inline struct file *open_firmware_file(PMINI_ADAPTER Adapter, char *path)
+static struct file *open_firmware_file(PMINI_ADAPTER Adapter, const char *path)
 {
     struct file             *flp=NULL;
     mm_segment_t        oldfs;
@@ -200,26 +192,20 @@ static inline struct file *open_firmware_file(PMINI_ADAPTER Adapter, char *path)
     set_fs(oldfs);
     if(IS_ERR(flp))
     {
-        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Unable To Open File %s, err  %lx",
-                               path, PTR_ERR(flp));
-               flp = NULL;
+           pr_err(DRV_NAME "Unable To Open File %s, err %ld",
+                  path, PTR_ERR(flp));
+           flp = NULL;
     }
-    else
-    {
-        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Got file descriptor pointer of %s!",
-                       path);
-    }
-       if(Adapter->device_removed)
-       {
-               flp = NULL;
-       }
+
+    if(Adapter->device_removed)
+           flp = NULL;
 
     return flp;
 }
 
 
-int BcmFileDownload(PMINI_ADAPTER Adapter,/**< Logical Adapter */
-                        char *path,     /**< path to image file */
+static int BcmFileDownload(PMINI_ADAPTER Adapter,/**< Logical Adapter */
+                        const char *path,     /**< path to image file */
                         unsigned int loc    /**< Download Address on the chip*/
                         )
 {
@@ -265,29 +251,8 @@ exit_download:
        if(flp && !(IS_ERR(flp)))
        filp_close(flp, current->files);
     set_fs(oldfs);
-    do_gettimeofday(&tv);
-    BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "file download done at %lx", ((tv.tv_sec * 1000) +
-                            (tv.tv_usec/1000)));
-    return errorno;
-}
 
-
-void bcm_kfree_skb(struct sk_buff *skb)
-{
-       if(skb)
-    {
-       kfree_skb(skb);
-    }
-       skb = NULL ;
-}
-
-VOID bcm_kfree(VOID *ptr)
-{
-       if(ptr)
-       {
-               kfree(ptr);
-       }
-       ptr = NULL ;
+    return errorno;
 }
 
 /**
@@ -395,13 +360,6 @@ INT CopyBufferToControlPacket(PMINI_ADAPTER Adapter,/**<Logical Adapter*/
                        /*Setting bIdleMode_tx_from_host to TRUE to indicate LED control thread to represent
                          the wake up from idlemode is from host*/
                        //Adapter->LEDInfo.bIdleMode_tx_from_host = TRUE;
-#if 0
-                       if(STATUS_SUCCESS != InterfaceIdleModeWakeup(Adapter))
-                       {
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Idle Mode Wake up Failed\n");
-                               return STATUS_FAILURE;
-                       }
-#endif
                        Adapter->bWakeUpDevice = TRUE;
                        wake_up(&Adapter->process_rx_cntrlpkt);
 
@@ -489,9 +447,6 @@ INT CopyBufferToControlPacket(PMINI_ADAPTER Adapter,/**<Logical Adapter*/
                atomic_inc(&Adapter->index_wr_txcntrlpkt);
                BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, TX_CONTROL,DBG_LVL_ALL, "Calling transmit_packets");
                atomic_set(&Adapter->TxPktAvail, 1);
-#ifdef BCM_SHM_INTERFACE
-               virtual_mail_box_interrupt();
-#endif
                wake_up(&Adapter->tx_packet_wait_queue);
        }
        else
@@ -530,18 +485,6 @@ static VOID SendStatisticsPointerRequest(PMINI_ADAPTER Adapter,
 #endif
 
 
-void SendLinkDown(PMINI_ADAPTER Adapter)
-{
-       LINK_REQUEST    stLinkDownRequest;
-       memset(&stLinkDownRequest, 0, sizeof(LINK_REQUEST));
-       stLinkDownRequest.Leader.Status=LINK_UP_CONTROL_REQ;
-       stLinkDownRequest.Leader.PLength=sizeof(ULONG);//minimum 4 bytes
-       stLinkDownRequest.szData[0]=LINK_DOWN_REQ_PAYLOAD;
-       Adapter->bLinkDownRequested = TRUE;
-
-       CopyBufferToControlPacket(Adapter,&stLinkDownRequest);
-}
-
 /******************************************************************
 * Function    - LinkMessage()
 *
@@ -552,7 +495,7 @@ void SendLinkDown(PMINI_ADAPTER Adapter)
 *
 * Returns     - None.
 *******************************************************************/
-__inline VOID LinkMessage(PMINI_ADAPTER Adapter)
+VOID LinkMessage(PMINI_ADAPTER Adapter)
 {
        PLINK_REQUEST   pstLinkRequest=NULL;
        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LINK_UP_MSG, DBG_LVL_ALL, "=====>");
@@ -594,7 +537,7 @@ __inline VOID LinkMessage(PMINI_ADAPTER Adapter)
        {
                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LINK_UP_MSG, DBG_LVL_ALL, "Calling CopyBufferToControlPacket");
                CopyBufferToControlPacket(Adapter, pstLinkRequest);
-               bcm_kfree(pstLinkRequest);
+               kfree(pstLinkRequest);
        }
        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LINK_UP_MSG, DBG_LVL_ALL, "LinkMessage <=====");
        return;
@@ -614,8 +557,8 @@ __inline VOID LinkMessage(PMINI_ADAPTER Adapter)
 VOID StatisticsResponse(PMINI_ADAPTER Adapter,PVOID pvBuffer)
 {
        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "%s====>",__FUNCTION__);
-       Adapter->StatisticsPointer = ntohl(*(PULONG)pvBuffer);
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "Stats at %lx", Adapter->StatisticsPointer);
+       Adapter->StatisticsPointer = ntohl(*(__be32 *)pvBuffer);
+       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "Stats at %x", (UINT)Adapter->StatisticsPointer);
        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "%s <====",__FUNCTION__);
        return;
 }
@@ -787,12 +730,10 @@ void SendIdleModeResponse(PMINI_ADAPTER Adapter)
                        down(&Adapter->rdmwrmsync);
                        Adapter->bPreparingForLowPowerMode = TRUE;
                        up(&Adapter->rdmwrmsync);
-#ifndef BCM_SHM_INTERFACE
                        //Killing all URBS.
                        if(Adapter->bDoSuspend == TRUE)
                                Bcm_kill_all_URBs((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter));
 
-#endif
                }
                else
                {
@@ -811,9 +752,7 @@ void SendIdleModeResponse(PMINI_ADAPTER Adapter)
        {
                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"fail to send the Idle mode Request \n");
                Adapter->bPreparingForLowPowerMode = FALSE;
-#ifndef BCM_SHM_INTERFACE
                StartInterruptUrb((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter));
-#endif
        }
        do_gettimeofday(&tv);
        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "IdleMode Msg submitter to Q :%ld ms", tv.tv_sec *1000 + tv.tv_usec /1000);
@@ -980,12 +919,10 @@ VOID DumpPackInfo(PMINI_ADAPTER Adapter)
 
 }
 
-
-__inline int reset_card_proc(PMINI_ADAPTER ps_adapter)
+int reset_card_proc(PMINI_ADAPTER ps_adapter)
 {
        int retval = STATUS_SUCCESS;
 
-#ifndef BCM_SHM_INTERFACE
     PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
        PS_INTERFACE_ADAPTER psIntfAdapter = NULL;
        unsigned int value = 0, uiResetValue = 0;
@@ -1006,11 +943,9 @@ __inline int reset_card_proc(PMINI_ADAPTER ps_adapter)
                wrmalt(ps_adapter, SYS_CFG, &value, sizeof(value));
        }
 
-#ifndef BCM_SHM_INTERFACE
        //killing all submitted URBs.
        psIntfAdapter->psAdapter->StopAllXaction = TRUE ;
        Bcm_kill_all_URBs(psIntfAdapter);
-#endif
        /* Reset the UMA-B Device */
        if(ps_adapter->chip_id >= T3LPB)
        {
@@ -1111,11 +1046,10 @@ __inline int reset_card_proc(PMINI_ADAPTER ps_adapter)
 
 err_exit :
        psIntfAdapter->psAdapter->StopAllXaction = FALSE ;
-#endif
        return retval;
 }
 
-__inline int run_card_proc(PMINI_ADAPTER ps_adapter )
+int run_card_proc(PMINI_ADAPTER ps_adapter )
 {
        unsigned int value=0;
        {
@@ -1148,19 +1082,15 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter)
 
        UINT status = STATUS_SUCCESS;
        UINT value = 0;
-#ifdef BCM_SHM_INTERFACE
-       unsigned char *pConfigFileAddr = (unsigned char *)CPE_MACXVI_CFG_ADDR;
-#endif
        /*
         * Create the threads first and then download the
         * Firm/DDR Settings..
         */
 
-       if((status = create_worker_threads(ps_adapter))<0)
-       {
-               BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Cannot create thread");
+       status = create_worker_threads(ps_adapter);
+       if (status<0)
                return status;
-       }
+
        /*
         * For Downloading the Firm, parse the cfg file first.
         */
@@ -1169,7 +1099,6 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter)
                return status;
        }
 
-#ifndef BCM_SHM_INTERFACE
        if(ps_adapter->chip_id >= T3LPB)
        {
                rdmalt(ps_adapter, SYS_CFG, &value, sizeof (value));
@@ -1187,7 +1116,7 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter)
        status = ddr_init(ps_adapter);
        if(status)
        {
-               BCM_DEBUG_PRINT (ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "ddr_init Failed\n");
+               pr_err(DRV_NAME "ddr_init Failed\n");
                return status;
        }
 
@@ -1201,7 +1130,6 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter)
                BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Error downloading CFG file");
                goto OUT;
        }
-       BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "CFG file downloaded");
 
        if(register_networkdev(ps_adapter))
        {
@@ -1266,12 +1194,6 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter)
                        goto OUT;
                }
        }
-#if 0
-       else if(psAdapter->eNVMType == NVM_EEPROM)
-       {
-               PropagateCalParamsFromEEPROMToMemory();
-       }
-#endif
 
        /* Download Firmare */
        if ((status = BcmFileDownload( ps_adapter, BIN_FILE, FIRMWARE_BEGIN_ADDR)))
@@ -1280,7 +1202,6 @@ int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter)
                goto OUT;
        }
 
-       BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "BIN file downloaded");
        status = run_card_proc(ps_adapter);
        if(status)
        {
@@ -1299,61 +1220,12 @@ OUT:
                wake_up(&ps_adapter->LEDInfo.notify_led_event);
        }
 
-#else
-
-       ps_adapter->bDDRInitDone = TRUE;
-       //Initializing the NVM.
-       BcmInitNVM(ps_adapter);
-
-       //Propagating the cal param from Flash to DDR
-       value = 0;
-       wrmalt(ps_adapter, EEPROM_CAL_DATA_INTERNAL_LOC - 4, &value, sizeof(value));
-       wrmalt(ps_adapter, EEPROM_CAL_DATA_INTERNAL_LOC - 8, &value, sizeof(value));
-
-       if(ps_adapter->eNVMType == NVM_FLASH)
-       {
-               status = PropagateCalParamsFromFlashToMemory(ps_adapter);
-               if(status)
-               {
-                       printk("\nPropogation of Cal param from flash to DDR failed ..\n" );
-               }
-       }
-
-       //Copy config file param to DDR.
-       memcpy(pConfigFileAddr,ps_adapter->pstargetparams, sizeof(STARGETPARAMS));
-
-       if(register_networkdev(ps_adapter))
-       {
-               BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Register Netdevice failed. Cleanup needs to be performed.");
-               return -EIO;
-       }
-
-
-       status = InitLedSettings (ps_adapter);
-       if(status)
-       {
-               BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_PRINTK, 0, 0,"INIT LED FAILED\n");
-               return status;
-       }
-
-
-       if(register_control_device_interface(ps_adapter) < 0)
-       {
-               BCM_DEBUG_PRINT(ps_adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Register Control Device failed. Cleanup needs to be performed.");
-               return -EIO;
-       }
-
-       ps_adapter->fw_download_done = TRUE;
-#endif
        return status;
 }
 
 
-int bcm_parse_target_params(PMINI_ADAPTER Adapter)
+static int bcm_parse_target_params(PMINI_ADAPTER Adapter)
 {
-#ifdef BCM_SHM_INTERFACE
-       extern void read_cfg_file(PMINI_ADAPTER Adapter);
-#endif
        struct file             *flp=NULL;
        mm_segment_t    oldfs={0};
        char *buff = NULL;
@@ -1368,14 +1240,14 @@ int bcm_parse_target_params(PMINI_ADAPTER Adapter)
        if((Adapter->pstargetparams =
                kmalloc(sizeof(STARGETPARAMS), GFP_KERNEL)) == NULL)
        {
-               bcm_kfree(buff);
+               kfree(buff);
                return -ENOMEM;
        }
        flp=open_firmware_file(Adapter, CFG_FILE);
        if(!flp) {
                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "NOT ABLE TO OPEN THE %s FILE \n", CFG_FILE);
-               bcm_kfree(buff);
-               bcm_kfree(Adapter->pstargetparams);
+               kfree(buff);
+               kfree(Adapter->pstargetparams);
                Adapter->pstargetparams = NULL;
                return -ENOENT;
        }
@@ -1386,8 +1258,8 @@ int bcm_parse_target_params(PMINI_ADAPTER Adapter)
        if(len != sizeof(STARGETPARAMS))
        {
                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL,"Mismatch in Target Param Structure!\n");
-               bcm_kfree(buff);
-               bcm_kfree(Adapter->pstargetparams);
+               kfree(buff);
+               kfree(Adapter->pstargetparams);
                Adapter->pstargetparams = NULL;
                filp_close(flp, current->files);
                return -ENOENT;
@@ -1399,12 +1271,8 @@ int bcm_parse_target_params(PMINI_ADAPTER Adapter)
         * Values in Adapter->pstargetparams are in network byte order
         */
        memcpy(Adapter->pstargetparams, buff, sizeof(STARGETPARAMS));
-       bcm_kfree (buff);
+       kfree (buff);
        beceem_parse_target_struct(Adapter);
-#ifdef BCM_SHM_INTERFACE
-       read_cfg_file(Adapter);
-
-#endif
        return STATUS_SUCCESS;
 }
 
@@ -1414,22 +1282,23 @@ void beceem_parse_target_struct(PMINI_ADAPTER Adapter)
 
        if(ntohl(Adapter->pstargetparams->m_u32PhyParameter2) & AUTO_SYNC_DISABLE)
        {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "AutoSyncup is Disabled\n");
+               pr_info(DRV_NAME ": AutoSyncup is Disabled\n");
                Adapter->AutoSyncup = FALSE;
        }
        else
        {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "AutoSyncup is Enabled\n");
+               pr_info(DRV_NAME ": AutoSyncup is Enabled\n");
                Adapter->AutoSyncup     = TRUE;
        }
+
        if(ntohl(Adapter->pstargetparams->HostDrvrConfig6) & AUTO_LINKUP_ENABLE)
        {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Enabling autolink up");
+               pr_info(DRV_NAME ": Enabling autolink up");
                Adapter->AutoLinkUp = TRUE;
        }
        else
        {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Disabling autolink up");
+               pr_info(DRV_NAME ": Disabling autolink up");
                Adapter->AutoLinkUp = FALSE;
        }
        // Setting the DDR Setting..
@@ -1438,59 +1307,54 @@ void beceem_parse_target_struct(PMINI_ADAPTER Adapter)
        Adapter->ulPowerSaveMode =
                        (ntohl(Adapter->pstargetparams->HostDrvrConfig6)>>12)&0x0F;
 
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "DDR Setting: %x\n", Adapter->DDRSetting);
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT,DBG_LVL_ALL, "Power Save Mode: %lx\n",
-                                                       Adapter->ulPowerSaveMode);
+       pr_info(DRV_NAME ": DDR Setting: %x\n", Adapter->DDRSetting);
+       pr_info(DRV_NAME ": Power Save Mode: %lx\n", Adapter->ulPowerSaveMode);
        if(ntohl(Adapter->pstargetparams->HostDrvrConfig6) & AUTO_FIRM_DOWNLOAD)
     {
-        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Enabling Auto Firmware Download\n");
+        pr_info(DRV_NAME ": Enabling Auto Firmware Download\n");
         Adapter->AutoFirmDld = TRUE;
     }
     else
     {
-        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Disabling Auto Firmware Download\n");
+        pr_info(DRV_NAME ": Disabling Auto Firmware Download\n");
         Adapter->AutoFirmDld = FALSE;
     }
        uiHostDrvrCfg6 = ntohl(Adapter->pstargetparams->HostDrvrConfig6);
        Adapter->bMipsConfig = (uiHostDrvrCfg6>>20)&0x01;
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL,"MIPSConfig   : 0x%X\n",Adapter->bMipsConfig);
+       pr_info(DRV_NAME ": MIPSConfig   : 0x%X\n",Adapter->bMipsConfig);
        //used for backward compatibility.
        Adapter->bDPLLConfig = (uiHostDrvrCfg6>>19)&0x01;
 
        Adapter->PmuMode= (uiHostDrvrCfg6 >> 24 ) & 0x03;
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "PMU MODE: %x", Adapter->PmuMode);
+       pr_info(DRV_NAME ": PMU MODE: %x", Adapter->PmuMode);
 
     if((uiHostDrvrCfg6 >> HOST_BUS_SUSPEND_BIT ) & (0x01))
     {
         Adapter->bDoSuspend = TRUE;
-        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Making DoSuspend TRUE as per configFile");
+        pr_info(DRV_NAME ": Making DoSuspend TRUE as per configFile");
     }
 
        uiEEPROMFlag = ntohl(Adapter->pstargetparams->m_u32EEPROMFlag);
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "uiEEPROMFlag  : 0x%X\n",uiEEPROMFlag);
+       pr_info(DRV_NAME ": uiEEPROMFlag  : 0x%X\n",uiEEPROMFlag);
        Adapter->eNVMType = (NVM_TYPE)((uiEEPROMFlag>>4)&0x3);
 
-
        Adapter->bStatusWrite = (uiEEPROMFlag>>6)&0x1;
-       //printk(("bStatusWrite   : 0x%X\n", Adapter->bStatusWrite));
 
        Adapter->uiSectorSizeInCFG = 1024*(0xFFFF & ntohl(Adapter->pstargetparams->HostDrvrConfig4));
-       //printk(("uiSectorSize   : 0x%X\n", Adapter->uiSectorSizeInCFG));
 
        Adapter->bSectorSizeOverride =(bool) ((ntohl(Adapter->pstargetparams->HostDrvrConfig4))>>16)&0x1;
-       //printk(MP_INIT,("bSectorSizeOverride   : 0x%X\n",Adapter->bSectorSizeOverride));
 
        if(ntohl(Adapter->pstargetparams->m_u32PowerSavingModeOptions) &0x01)
                Adapter->ulPowerSaveMode = DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE;
-       //autocorrection part
+
        if(Adapter->ulPowerSaveMode != DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE)
                doPowerAutoCorrection(Adapter);
 
 }
 
-VOID doPowerAutoCorrection(PMINI_ADAPTER psAdapter)
+static VOID doPowerAutoCorrection(PMINI_ADAPTER psAdapter)
 {
-       UINT reporting_mode = 0;
+       UINT reporting_mode;
 
        reporting_mode = ntohl(psAdapter->pstargetparams->m_u32PowerSavingModeOptions) &0x02 ;
        psAdapter->bIsAutoCorrectEnabled = !((char)(psAdapter->ulPowerSaveMode >> 3) & 0x1);
@@ -1504,20 +1368,9 @@ VOID doPowerAutoCorrection(PMINI_ADAPTER psAdapter)
        if (psAdapter->bIsAutoCorrectEnabled && (psAdapter->chip_id >= T3LPB))
        {
                //If reporting mode is enable, switch PMU to PMC
-               #if 0
-               if(reporting_mode == FALSE)
-               {
-                       psAdapter->ulPowerSaveMode = DEVICE_POWERSAVE_MODE_AS_PMU_SHUTDOWN;
-                       psAdapter->bDoSuspend = TRUE;
-                       BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL,"PMU selected ....");
-
-               }
-               else
-               #endif
                {
                        psAdapter->ulPowerSaveMode = DEVICE_POWERSAVE_MODE_AS_PMU_CLOCK_GATING;
                        psAdapter->bDoSuspend =FALSE;
-                       BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL,"PMC selected..");
 
                }
 
@@ -1558,7 +1411,7 @@ static unsigned char *ReadMacAddrEEPROM(PMINI_ADAPTER Adapter, ulong dwAddress)
        if(status != STATUS_SUCCESS)
        {
                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "wrm Failed..\n");
-               bcm_kfree(pucmacaddr);
+               kfree(pucmacaddr);
                pucmacaddr = NULL;
                goto OUT;
        }
@@ -1568,7 +1421,7 @@ static unsigned char *ReadMacAddrEEPROM(PMINI_ADAPTER Adapter, ulong dwAddress)
                if(status != STATUS_SUCCESS)
                {
                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "rdm Failed..\n");
-                       bcm_kfree(pucmacaddr);
+                       kfree(pucmacaddr);
                        pucmacaddr = NULL;
                        goto OUT;
                }
@@ -1580,43 +1433,6 @@ OUT:
 }
 #endif
 
-#if 0
-INT ReadMacAddressFromEEPROM(PMINI_ADAPTER Adapter)
-{
-       unsigned char *puMacAddr = NULL;
-       int i =0;
-
-       puMacAddr = ReadMacAddrEEPROM(Adapter,0x200);
-       if(!puMacAddr)
-       {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Couldn't retrieve the Mac Address\n");
-               return STATUS_FAILURE;
-       }
-       else
-       {
-               if((puMacAddr[0] == 0x0  && puMacAddr[1] == 0x0  &&
-                       puMacAddr[2] == 0x0  && puMacAddr[3] == 0x0  &&
-                       puMacAddr[4] == 0x0  && puMacAddr[5] == 0x0) ||
-                  (puMacAddr[0] == 0xFF && puMacAddr[1] == 0xFF &&
-                       puMacAddr[2] == 0xFF && puMacAddr[3] == 0xFF &&
-                       puMacAddr[4] == 0xFF && puMacAddr[5] == 0xFF))
-               {
-                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Invalid Mac Address\n");
-                       bcm_kfree(puMacAddr);
-                       return STATUS_FAILURE;
-               }
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "The Mac Address received is: \n");
-               memcpy(Adapter->dev->dev_addr, puMacAddr, MAC_ADDRESS_SIZE);
-        for(i=0;i<MAC_ADDRESS_SIZE;i++)
-        {
-            BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"%02x ", Adapter->dev->dev_addr[i]);
-        }
-        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"\n");
-               bcm_kfree(puMacAddr);
-       }
-       return STATUS_SUCCESS;
-}
-#endif
 
 static void convertEndian(B_UINT8 rwFlag, PUINT puiBuffer, UINT uiByteCount)
 {
@@ -1640,81 +1456,21 @@ int rdm(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t sSize)
 {
        INT uiRetVal =0;
 
-#ifndef BCM_SHM_INTERFACE
        uiRetVal = Adapter->interface_rdm(Adapter->pvInterfaceAdapter,
                        uiAddress, pucBuff, sSize);
 
        if(uiRetVal < 0)
                return uiRetVal;
 
-#else
-       int indx;
-       uiRetVal = STATUS_SUCCESS;
-       if(uiAddress & 0x10000000) {
-                       // DDR Memory Access
-               uiAddress |= CACHE_ADDRESS_MASK;
-               memcpy(pucBuff,(unsigned char *)uiAddress ,sSize);
-       }
-       else {
-               // Register, SPRAM, Flash
-               uiAddress |= UNCACHE_ADDRESS_MASK;
-    if ((uiAddress & FLASH_ADDR_MASK) == (FLASH_CONTIGIOUS_START_ADDR_BCS350 & FLASH_ADDR_MASK))
-       {
-               #if defined(FLASH_DIRECT_ACCESS)
-               memcpy(pucBuff,(unsigned char *)uiAddress ,sSize);
-               #else
-                       printk("\nInvalid GSPI ACCESS :Addr :%#X", uiAddress);
-                       uiRetVal = STATUS_FAILURE;
-               #endif
-       }
-    else if(((unsigned int )uiAddress & 0x3) ||
-                       ((unsigned int )pucBuff & 0x3) ||
-                       ((unsigned int )sSize & 0x3)) {
-                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"rdmalt :unalligned register access uiAddress =  %x,pucBuff = %x  size = %x\n",(unsigned int )uiAddress,(unsigned int )pucBuff,(unsigned int )sSize);
-                        uiRetVal = STATUS_FAILURE;
-               }
-               else {
-                       for (indx=0;indx<sSize;indx+=4){
-                               *(PUINT)(pucBuff + indx) = *(PUINT)(uiAddress + indx);
-                       }
-               }
-       }
-#endif
        return uiRetVal;
 }
 int wrm(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t sSize)
 {
        int iRetVal;
 
-#ifndef BCM_SHM_INTERFACE
        iRetVal = Adapter->interface_wrm(Adapter->pvInterfaceAdapter,
                        uiAddress, pucBuff, sSize);
 
-#else
-       int indx;
-       if(uiAddress & 0x10000000) {
-               // DDR Memory Access
-               uiAddress |= CACHE_ADDRESS_MASK;
-               memcpy((unsigned char *)(uiAddress),pucBuff,sSize);
-       }
-       else {
-               // Register, SPRAM, Flash
-               uiAddress |= UNCACHE_ADDRESS_MASK;
-
-               if(((unsigned int )uiAddress & 0x3) ||
-                       ((unsigned int )pucBuff & 0x3) ||
-                       ((unsigned int )sSize & 0x3)) {
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"wrmalt: unalligned register access uiAddress =  %x,pucBuff = %x  size = %x\n",(unsigned int )uiAddress,(unsigned int )pucBuff,(unsigned int )sSize);
-                        iRetVal = STATUS_FAILURE;
-               }
-               else {
-                       for (indx=0;indx<sSize;indx+=4) {
-                               *(PUINT)(uiAddress + indx) = *(PUINT)(pucBuff + indx);
-                       }
-               }
-       }
-       iRetVal = STATUS_SUCCESS;
-#endif
 
        return iRetVal;
 }
@@ -1735,26 +1491,7 @@ int rdmalt (PMINI_ADAPTER Adapter, UINT uiAddress, PUINT pucBuff, size_t size)
        return uiRetVal;
 }
 
-int rdmWithLock(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t sSize)
-{
-
-       INT status = STATUS_SUCCESS ;
-       down(&Adapter->rdmwrmsync);
 
-       if((Adapter->IdleMode == TRUE) ||
-               (Adapter->bShutStatus ==TRUE) ||
-               (Adapter->bPreparingForLowPowerMode ==TRUE))
-       {
-               status = -EACCES;
-               goto exit;
-       }
-
-       status = rdm(Adapter, uiAddress, pucBuff, sSize);
-
-exit:
-       up(&Adapter->rdmwrmsync);
-       return status ;
-}
 int wrmWithLock(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t sSize)
 {
        INT status = STATUS_SUCCESS ;
@@ -1921,10 +1658,8 @@ static VOID SendShutModeResponse(PMINI_ADAPTER Adapter)
                        Adapter->bPreparingForLowPowerMode = TRUE;
                        up(&Adapter->rdmwrmsync);
                        //Killing all URBS.
-#ifndef BCM_SHM_INTERFACE
                        if(Adapter->bDoSuspend == TRUE)
                                Bcm_kill_all_URBs((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter));
-#endif
                }
                else
                {
@@ -1943,14 +1678,12 @@ static VOID SendShutModeResponse(PMINI_ADAPTER Adapter)
                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, MP_SHUTDOWN, DBG_LVL_ALL,"fail to send the Idle mode Request \n");
                Adapter->bPreparingForLowPowerMode = FALSE;
 
-#ifndef BCM_SHM_INTERFACE
                StartInterruptUrb((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter));
-#endif
        }
 }
 
 
-void HandleShutDownModeRequest(PMINI_ADAPTER Adapter,PUCHAR pucBuffer)
+static void HandleShutDownModeRequest(PMINI_ADAPTER Adapter,PUCHAR pucBuffer)
 {
        B_UINT32 uiResetValue = 0;
 
@@ -2077,11 +1810,7 @@ void update_per_sf_desc_cnts( PMINI_ADAPTER Adapter)
        if(!atomic_read (&Adapter->uiMBupdate))
                return;
 
-#ifdef BCM_SHM_INTERFACE
-       if(rdmalt(Adapter, TARGET_SFID_TXDESC_MAP_LOC, (PUINT)uibuff, sizeof(UINT) * MAX_TARGET_DSX_BUFFERS)<0)
-#else
        if(rdmaltWithLock(Adapter, TARGET_SFID_TXDESC_MAP_LOC, (PUINT)uibuff, sizeof(UINT) * MAX_TARGET_DSX_BUFFERS)<0)
-#endif
        {
                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "rdm failed\n");
                return;
@@ -2107,9 +1836,7 @@ void update_per_sf_desc_cnts( PMINI_ADAPTER Adapter)
 void flush_queue(PMINI_ADAPTER Adapter, UINT iQIndex)
 {
        struct sk_buff*                         PacketToDrop=NULL;
-       struct net_device_stats*                netstats=NULL;
-
-       netstats = &((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats;
+       struct net_device_stats*                netstats = &Adapter->dev->stats;
 
        spin_lock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock);
 
@@ -2130,25 +1857,23 @@ void flush_queue(PMINI_ADAPTER Adapter, UINT iQIndex)
                        Adapter->PackInfo[iQIndex].uiDroppedCountBytes += PacketToDrop->len;
                        Adapter->PackInfo[iQIndex].uiDroppedCountPackets++;
 
-                       bcm_kfree_skb(PacketToDrop);
+                       dev_kfree_skb(PacketToDrop);
                        atomic_dec(&Adapter->TotalPacketCount);
-                       atomic_inc(&Adapter->TxDroppedPacketCount);
-
                }
        }
        spin_unlock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock);
 
 }
 
-void beceem_protocol_reset (PMINI_ADAPTER Adapter)
+static void beceem_protocol_reset (PMINI_ADAPTER Adapter)
 {
-       int i =0;
+       int i;
 
-       if(NULL != Adapter->dev)
-       {
-               netif_carrier_off(Adapter->dev);
-               netif_stop_queue(Adapter->dev);
-       }
+       if (netif_msg_link(Adapter))
+               pr_notice(PFX "%s: protocol reset\n", Adapter->dev->name);
+
+       netif_carrier_off(Adapter->dev);
+       netif_stop_queue(Adapter->dev);
 
        Adapter->IdleMode = FALSE;
        Adapter->LinkUpStatus = FALSE;
@@ -2166,78 +1891,18 @@ void beceem_protocol_reset (PMINI_ADAPTER Adapter)
                Adapter->TimerActive = FALSE;
 
        memset(Adapter->astFragmentedPktClassifierTable, 0,
-                       sizeof(S_FRAGMENTED_PACKET_INFO) *
-                       MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES);
+              sizeof(S_FRAGMENTED_PACKET_INFO) * MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES);
 
        for(i = 0;i<HiPriority;i++)
        {
                //resetting only the first size (S_MIBS_SERVICEFLOW_TABLE) for the SF.
                // It is same between MIBs and SF.
-               memset((PVOID)&Adapter->PackInfo[i],0,sizeof(S_MIBS_SERVICEFLOW_TABLE));
+               memset(&Adapter->PackInfo[i].stMibsExtServiceFlowTable,
+                      0, sizeof(S_MIBS_EXTSERVICEFLOW_PARAMETERS));
        }
 }
 
 
 
-#ifdef BCM_SHM_INTERFACE
-
-
-#define GET_GTB_DIFF(start, end)  \
-( (start) < (end) )? ( (end) - (start) ) : ( ~0x0 - ( (start) - (end)) +1 )
-
-void usdelay ( unsigned int a) {
-       unsigned int start= *(unsigned int *)0xaf8051b4;
-       unsigned int end  = start+1;
-       unsigned int diff = 0;
-
-       while(1) {
-               end = *(unsigned int *)0xaf8051b4;
-               diff = (GET_GTB_DIFF(start,end))/80;
-               if (diff >= a)
-                       break;
-       }
-}
-void read_cfg_file(PMINI_ADAPTER Adapter) {
-
-
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Config File Version = 0x%x \n",Adapter->pstargetparams->m_u32CfgVersion );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Center Frequency =  0x%x \n",Adapter->pstargetparams->m_u32CenterFrequency );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Band A Scan = 0x%x \n",Adapter->pstargetparams->m_u32BandAScan );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Band B Scan = 0x%x \n",Adapter->pstargetparams->m_u32BandBScan );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Band C Scan = 0x%x \n",Adapter->pstargetparams->m_u32BandCScan );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"ERTPS Options = 0x%x \n",Adapter->pstargetparams->m_u32ErtpsOptions );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"PHS Enable = 0x%x \n",Adapter->pstargetparams->m_u32PHSEnable );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Handoff Enable = 0x%x \n",Adapter->pstargetparams->m_u32HoEnable );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HO Reserved1 = 0x%x \n",Adapter->pstargetparams->m_u32HoReserved1 );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HO Reserved2 = 0x%x \n",Adapter->pstargetparams->m_u32HoReserved2 );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"MIMO Enable = 0x%x \n",Adapter->pstargetparams->m_u32MimoEnable );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"PKMv2 Enable = 0x%x \n",Adapter->pstargetparams->m_u32SecurityEnable );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Powersaving Modes Enable = 0x%x \n",Adapter->pstargetparams->m_u32PowerSavingModesEnable );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Power Saving Mode Options = 0x%x \n",Adapter->pstargetparams->m_u32PowerSavingModeOptions );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"ARQ Enable = 0x%x \n",Adapter->pstargetparams->m_u32ArqEnable );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Harq Enable = 0x%x \n",Adapter->pstargetparams->m_u32HarqEnable );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"EEPROM Flag = 0x%x \n",Adapter->pstargetparams->m_u32EEPROMFlag );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Customize = 0x%x \n",Adapter->pstargetparams->m_u32Customize );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Bandwidth = 0x%x \n",Adapter->pstargetparams->m_u32ConfigBW );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"ShutDown Timer Value = 0x%x \n",Adapter->pstargetparams->m_u32ShutDownInitThresholdTimer );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"RadioParameter = 0x%x \n",Adapter->pstargetparams->m_u32RadioParameter );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"PhyParameter1 = 0x%x \n",Adapter->pstargetparams->m_u32PhyParameter1 );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"PhyParameter2 = 0x%x \n",Adapter->pstargetparams->m_u32PhyParameter2 );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"PhyParameter3 = 0x%x \n",Adapter->pstargetparams->m_u32PhyParameter3 );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"m_u32TestOptions = 0x%x \n",Adapter->pstargetparams->m_u32TestOptions );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"MaxMACDataperDLFrame = 0x%x \n",Adapter->pstargetparams->m_u32MaxMACDataperDLFrame );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"MaxMACDataperULFrame = 0x%x \n",Adapter->pstargetparams->m_u32MaxMACDataperULFrame );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Corr2MacFlags = 0x%x \n",Adapter->pstargetparams->m_u32Corr2MacFlags );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HostDrvrConfig1 = 0x%x \n",Adapter->pstargetparams->HostDrvrConfig1 );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HostDrvrConfig2 = 0x%x \n",Adapter->pstargetparams->HostDrvrConfig2 );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HostDrvrConfig3 = 0x%x \n",Adapter->pstargetparams->HostDrvrConfig3 );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HostDrvrConfig4 = 0x%x \n",Adapter->pstargetparams->HostDrvrConfig4 );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HostDrvrConfig5 = 0x%x \n",Adapter->pstargetparams->HostDrvrConfig5 );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"HostDrvrConfig6 = 0x%x \n",Adapter->pstargetparams->HostDrvrConfig6 );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Segmented PUSC Enable = 0x%x \n",Adapter->pstargetparams->m_u32SegmentedPUSCenable );
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"BamcEnable = 0x%x \n",Adapter->pstargetparams->m_u32BandAMCEnable );
-}
-
-#endif
 
 
diff --git a/drivers/staging/bcm/Osal_Misc.c b/drivers/staging/bcm/Osal_Misc.c
deleted file mode 100644 (file)
index feefd20..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-       /*++
-
-       Copyright (c) Beceem Communications Inc.
-
-       Module Name:
-               WIN_Misc.c
-
-       Abstract:
-               Implements the Miscelanneous OS Construts
-                       Linked Lists
-                       Dispatcher Objects(Events,Semaphores,Spin Locks and the like)
-                       Files
-
-       Revision History:
-               Who         When        What
-               --------    --------    ----------------------------------------------
-               Name            Date            Created/reviewed/modified
-               Rajeev          24/1/08         Created
-       Notes:
-
-       --*/
-#include "headers.h"
-
-bool OsalMemCompare(void *dest, void *src, UINT len)
-{
-       return (memcmp(src, dest, len));
-}
index 8a38cf43e79549cbfe39450179f71075843e3ee2..d1ca1912a74bffa0b1efa9a9fd9b5f1466b1e10f 100644 (file)
@@ -1,10 +1,54 @@
 #include "headers.h"
 
+static UINT CreateSFToClassifierRuleMapping(B_UINT16 uiVcid,B_UINT16  uiClsId,S_SERVICEFLOW_TABLE *psServiceFlowTable,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI);
+
+static UINT CreateClassiferToPHSRuleMapping(B_UINT16 uiVcid,B_UINT16  uiClsId,S_SERVICEFLOW_ENTRY *pstServiceFlowEntry,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI);
+
+static UINT CreateClassifierPHSRule(B_UINT16  uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,B_UINT8 u8AssociatedPHSI);
+
+static UINT UpdateClassifierPHSRule(B_UINT16  uiClsId,S_CLASSIFIER_ENTRY *pstClassifierEntry,S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI);
+
+static BOOLEAN ValidatePHSRuleComplete(S_PHS_RULE *psPhsRule);
+
+static BOOLEAN DerefPhsRule(B_UINT16  uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable,S_PHS_RULE *pstPhsRule);
+
+static UINT GetClassifierEntry(S_CLASSIFIER_TABLE *pstClassifierTable,B_UINT32 uiClsid,E_CLASSIFIER_ENTRY_CONTEXT eClsContext, S_CLASSIFIER_ENTRY **ppstClassifierEntry);
+
+static UINT GetPhsRuleEntry(S_CLASSIFIER_TABLE *pstClassifierTable,B_UINT32 uiPHSI,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,S_PHS_RULE **ppstPhsRule);
+
+static void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable);
+
+static int phs_compress(S_PHS_RULE   *phs_members,unsigned char *in_buf,
+                                               unsigned char *out_buf,unsigned int *header_size,UINT *new_header_size );
+
+
+static int verify_suppress_phsf(unsigned char *in_buffer,unsigned char *out_buffer,
+                                                               unsigned char *phsf,unsigned char *phsm,unsigned int phss,unsigned int phsv,UINT *new_header_size );
+
+static int phs_decompress(unsigned char *in_buf,unsigned char *out_buf,\
+                                                 S_PHS_RULE   *phs_rules,UINT *header_size);
+
+
+static ULONG PhsCompress(void* pvContext,
+                                 B_UINT16 uiVcid,
+                                 B_UINT16 uiClsId,
+                                 void *pvInputBuffer,
+                                 void *pvOutputBuffer,
+                                 UINT *pOldHeaderSize,
+                                 UINT *pNewHeaderSize );
+
+static ULONG PhsDeCompress(void* pvContext,
+                                 B_UINT16 uiVcid,
+                                 void *pvInputBuffer,
+                                 void *pvOutputBuffer,
+                                 UINT *pInHeaderSize,
+                                 UINT *pOutHeaderSize);
+
+
+
 #define IN
 #define OUT
 
-void DumpDataPacketHeader(PUCHAR pPkt);
-
 /*
 Function:                              PHSTransmit
 
@@ -81,8 +125,6 @@ int PHSTransmit(PMINI_ADAPTER Adapter,
        {
 
 
-               //DumpDataPacketHeader(pucPHSPktHdrInBuf);
-
                // Step 2 Supress Header using PHS and fill into intermediate ucaPHSPktHdrOutBuf.
        // Suppress only if IP Header and PHS Enabled For the Service Flow
                if(((usPacketType == ETHERNET_FRAMETYPE_IPV4) ||
@@ -120,15 +162,15 @@ int PHSTransmit(PMINI_ADAPTER Adapter,
                                                if(newPacket == NULL)
                                                        return STATUS_FAILURE;
 
-                                               bcm_kfree_skb(Packet);
+                                               dev_kfree_skb(Packet);
                                                *pPacket = Packet = newPacket;
                                                pucPHSPktHdrInBuf = Packet->data  + BytesToRemove;
                                        }
 
                                        numBytesCompressed = unPhsOldHdrSize - (unPHSNewPktHeaderLen+PHSI_LEN);
 
-                                       OsalMemMove(pucPHSPktHdrInBuf + numBytesCompressed, pucPHSPktHdrOutBuf, unPHSNewPktHeaderLen + PHSI_LEN);
-                                       OsalMemMove(Packet->data + numBytesCompressed, Packet->data, BytesToRemove);
+                                       memcpy(pucPHSPktHdrInBuf + numBytesCompressed, pucPHSPktHdrOutBuf, unPHSNewPktHeaderLen + PHSI_LEN);
+                                       memcpy(Packet->data + numBytesCompressed, Packet->data, BytesToRemove);
                                        skb_pull(Packet, numBytesCompressed);
 
                                        return STATUS_SUCCESS;
@@ -223,23 +265,12 @@ int PHSRecieve(PMINI_ADAPTER Adapter,
                        }
                }
 
-               OsalMemMove(packet->data, Adapter->ucaPHSPktRestoreBuf, nStandardPktHdrLen);
+               memcpy(packet->data, Adapter->ucaPHSPktRestoreBuf, nStandardPktHdrLen);
        }
 
        return STATUS_SUCCESS;
 }
 
-void DumpDataPacketHeader(PUCHAR pPkt)
-{
-       struct iphdr *iphd = (struct iphdr*)pPkt;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"Phs Send/Recieve : IP Packet Hdr \n");
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"TOS : %x \n",iphd->tos);
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"Src  IP : %x \n",iphd->saddr);
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"Dest IP : %x \n \n",iphd->daddr);
-
-}
-
 void DumpFullPacket(UCHAR *pBuf,UINT nPktLen)
 {
        PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
@@ -270,15 +301,9 @@ int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension,PMINI_ADAPTER Adapter)
                return -EINVAL;
 
        pPhsdeviceExtension->pstServiceFlowPhsRulesTable =
-      (S_SERVICEFLOW_TABLE*)OsalMemAlloc(sizeof(S_SERVICEFLOW_TABLE),
-            PHS_MEM_TAG);
+               kzalloc(sizeof(S_SERVICEFLOW_TABLE), GFP_KERNEL);
 
-    if(pPhsdeviceExtension->pstServiceFlowPhsRulesTable)
-       {
-               OsalZeroMemory(pPhsdeviceExtension->pstServiceFlowPhsRulesTable,
-              sizeof(S_SERVICEFLOW_TABLE));
-       }
-       else
+    if(!pPhsdeviceExtension->pstServiceFlowPhsRulesTable)
        {
                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation ServiceFlowPhsRulesTable failed");
                return -ENOMEM;
@@ -288,14 +313,8 @@ int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension,PMINI_ADAPTER Adapter)
        for(i=0;i<MAX_SERVICEFLOWS;i++)
        {
                S_SERVICEFLOW_ENTRY sServiceFlow = pstServiceFlowTable->stSFList[i];
-               sServiceFlow.pstClassifierTable = (S_CLASSIFIER_TABLE*)OsalMemAlloc(
-            sizeof(S_CLASSIFIER_TABLE), PHS_MEM_TAG);
-               if(sServiceFlow.pstClassifierTable)
-               {
-                       OsalZeroMemory(sServiceFlow.pstClassifierTable,sizeof(S_CLASSIFIER_TABLE));
-                       pstServiceFlowTable->stSFList[i].pstClassifierTable = sServiceFlow.pstClassifierTable;
-       }
-               else
+               sServiceFlow.pstClassifierTable = kzalloc(sizeof(S_CLASSIFIER_TABLE), GFP_KERNEL);
+               if(!sServiceFlow.pstClassifierTable)
                {
                        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed");
                        free_phs_serviceflow_rules(pPhsdeviceExtension->
@@ -305,9 +324,7 @@ int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension,PMINI_ADAPTER Adapter)
                }
        }
 
-
-       pPhsdeviceExtension->CompressedTxBuffer =
-          OsalMemAlloc(PHS_BUFFER_SIZE,PHS_MEM_TAG);
+       pPhsdeviceExtension->CompressedTxBuffer = kmalloc(PHS_BUFFER_SIZE, GFP_KERNEL);
 
     if(pPhsdeviceExtension->CompressedTxBuffer == NULL)
        {
@@ -317,12 +334,11 @@ int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension,PMINI_ADAPTER Adapter)
                return -ENOMEM;
        }
 
-       pPhsdeviceExtension->UnCompressedRxBuffer =
-      OsalMemAlloc(PHS_BUFFER_SIZE,PHS_MEM_TAG);
+    pPhsdeviceExtension->UnCompressedRxBuffer = kmalloc(PHS_BUFFER_SIZE, GFP_KERNEL);
        if(pPhsdeviceExtension->UnCompressedRxBuffer == NULL)
        {
                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed");
-               OsalMemFree(pPhsdeviceExtension->CompressedTxBuffer,PHS_BUFFER_SIZE);
+               kfree(pPhsdeviceExtension->CompressedTxBuffer);
                free_phs_serviceflow_rules(pPhsdeviceExtension->pstServiceFlowPhsRulesTable);
                pPhsdeviceExtension->pstServiceFlowPhsRulesTable = NULL;
                return -ENOMEM;
@@ -343,16 +359,11 @@ int PhsCleanup(IN PPHS_DEVICE_EXTENSION pPHSDeviceExt)
                pPHSDeviceExt->pstServiceFlowPhsRulesTable = NULL;
        }
 
-       if(pPHSDeviceExt->CompressedTxBuffer)
-       {
-               OsalMemFree(pPHSDeviceExt->CompressedTxBuffer,PHS_BUFFER_SIZE);
-               pPHSDeviceExt->CompressedTxBuffer = NULL;
-       }
-       if(pPHSDeviceExt->UnCompressedRxBuffer)
-       {
-               OsalMemFree(pPHSDeviceExt->UnCompressedRxBuffer,PHS_BUFFER_SIZE);
-               pPHSDeviceExt->UnCompressedRxBuffer = NULL;
-       }
+       kfree(pPHSDeviceExt->CompressedTxBuffer);
+       pPHSDeviceExt->CompressedTxBuffer = NULL;
+
+       kfree(pPHSDeviceExt->UnCompressedRxBuffer);
+       pPHSDeviceExt->UnCompressedRxBuffer = NULL;
 
        return 0;
 }
@@ -478,20 +489,12 @@ ULONG PhsDeletePHSRule(IN void* pvContext,IN B_UINT16 uiVcid,IN B_UINT8 u8PHSI)
                        {
                                if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].bUsed && pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule)
                                {
-                                       if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex]
-                                        .pstPhsRule->u8PHSI == u8PHSI)
-                                       {
-                                               if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule
-                                                ->u8RefCnt)
-                                                       pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule
-                                                         ->u8RefCnt--;
-                                               if(0 == pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex]
-                            .pstPhsRule->u8RefCnt)
-                                                       OsalMemFree(pstClassifierRulesTable
-                                                   ->stActivePhsRulesList[nClsidIndex].pstPhsRule,
-                                                     sizeof(S_PHS_RULE));
-                                               OsalZeroMemory(&pstClassifierRulesTable
-                                                       ->stActivePhsRulesList[nClsidIndex],
+                                       if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8PHSI == u8PHSI)                                     {
+                                               if(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
+                                                       pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt--;
+                                               if(0 == pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt)
+                                                       kfree(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule);
+                                               memset(&pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex], 0,
                                                        sizeof(S_CLASSIFIER_ENTRY));
                                        }
                                }
@@ -548,10 +551,10 @@ ULONG PhsDeleteClassifierRule(IN void* pvContext,IN B_UINT16 uiVcid ,IN B_UINT16
                                if(pstClassifierEntry->pstPhsRule->u8RefCnt)
                                pstClassifierEntry->pstPhsRule->u8RefCnt--;
                                if(0==pstClassifierEntry->pstPhsRule->u8RefCnt)
-                               OsalMemFree(pstClassifierEntry->pstPhsRule,sizeof(S_PHS_RULE));
+                                       kfree(pstClassifierEntry->pstPhsRule);
 
                        }
-                       OsalZeroMemory(pstClassifierEntry,sizeof(S_CLASSIFIER_ENTRY));
+                       memset(pstClassifierEntry, 0, sizeof(S_CLASSIFIER_ENTRY));
                }
 
                nClsidIndex = GetClassifierEntry(pstServiceFlowEntry->pstClassifierTable,
@@ -559,10 +562,8 @@ ULONG PhsDeleteClassifierRule(IN void* pvContext,IN B_UINT16 uiVcid ,IN B_UINT16
 
           if((nClsidIndex != PHS_INVALID_TABLE_INDEX) && (!pstClassifierEntry->bUnclassifiedPHSRule))
                {
-                       if(pstClassifierEntry->pstPhsRule)
-                       //Delete the classifier entry
-                       OsalMemFree(pstClassifierEntry->pstPhsRule,sizeof(S_PHS_RULE));
-                       OsalZeroMemory(pstClassifierEntry,sizeof(S_CLASSIFIER_ENTRY));
+                       kfree(pstClassifierEntry->pstPhsRule);
+                       memset(pstClassifierEntry, 0, sizeof(S_CLASSIFIER_ENTRY));
                }
        }
        return lStatus;
@@ -619,14 +620,11 @@ ULONG PhsDeleteSFRules(IN void* pvContext,IN B_UINT16 uiVcid)
                                                                                    .pstPhsRule->u8RefCnt--;
                                        if(0==pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex]
                                                           .pstPhsRule->u8RefCnt)
-                                               OsalMemFree(pstClassifierRulesTable
-                                                           ->stActivePhsRulesList[nClsidIndex].pstPhsRule,
-                                                            sizeof(S_PHS_RULE));
+                                               kfree(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule);
                                            pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex]
                                         .pstPhsRule = NULL;
                                }
-                               OsalZeroMemory(&pstClassifierRulesTable
-                    ->stActivePhsRulesList[nClsidIndex],sizeof(S_CLASSIFIER_ENTRY));
+                               memset(&pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex], 0, sizeof(S_CLASSIFIER_ENTRY));
                                if(pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule)
                                {
                                        if(pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex]
@@ -635,15 +633,12 @@ ULONG PhsDeleteSFRules(IN void* pvContext,IN B_UINT16 uiVcid)
                                                                  .pstPhsRule->u8RefCnt--;
                                        if(0 == pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex]
                                         .pstPhsRule->u8RefCnt)
-                                               OsalMemFree(pstClassifierRulesTable
-                                                     ->stOldPhsRulesList[nClsidIndex].pstPhsRule,
-                                                      sizeof(S_PHS_RULE));
+                                               kfree(pstClassifierRulesTable
+                                                     ->stOldPhsRulesList[nClsidIndex].pstPhsRule);
                                        pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex]
                               .pstPhsRule = NULL;
                                }
-                               OsalZeroMemory(&pstClassifierRulesTable
-                  ->stOldPhsRulesList[nClsidIndex],
-                   sizeof(S_CLASSIFIER_ENTRY));
+                               memset(&pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex], 0, sizeof(S_CLASSIFIER_ENTRY));
                        }
                }
                pstServiceFlowEntry->bUsed = FALSE;
@@ -849,7 +844,7 @@ ULONG PhsDeCompress(IN void* pvContext,
 // Does not return any value.
 //-----------------------------------------------------------------------------
 
-void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable)
+static void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable)
 {
        int i,j;
     PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
@@ -876,8 +871,7 @@ void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable)
                                                                                                        ->u8RefCnt--;
                                                if(0==pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule
                                                                 ->u8RefCnt)
-                                                       OsalMemFree(pstClassifierRulesTable->stActivePhsRulesList[j].
-                                                                                                     pstPhsRule, sizeof(S_PHS_RULE));
+                                                       kfree(pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule);
                                                pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule = NULL;
                                        }
                                        if(pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule)
@@ -888,24 +882,23 @@ void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable)
                                                                                                  ->u8RefCnt--;
                                                if(0==pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule
                                                                       ->u8RefCnt)
-                                                       OsalMemFree(pstClassifierRulesTable->stOldPhsRulesList[j]
-                                                                               .pstPhsRule,sizeof(S_PHS_RULE));
+                                                       kfree(pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule);
                                                pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule = NULL;
                                        }
                                }
-                           OsalMemFree(pstClassifierRulesTable,sizeof(S_CLASSIFIER_TABLE));
+                               kfree(pstClassifierRulesTable);
                            stServiceFlowEntry.pstClassifierTable = pstClassifierRulesTable = NULL;
                        }
                }
        }
 
-       OsalMemFree(psServiceFlowRulesTable,sizeof(S_SERVICEFLOW_TABLE));
-       psServiceFlowRulesTable = NULL;
+    kfree(psServiceFlowRulesTable);
+    psServiceFlowRulesTable = NULL;
 }
 
 
 
-BOOLEAN ValidatePHSRuleComplete(IN S_PHS_RULE *psPhsRule)
+static BOOLEAN ValidatePHSRuleComplete(IN S_PHS_RULE *psPhsRule)
 {
        if(psPhsRule)
        {
@@ -988,9 +981,9 @@ UINT GetClassifierEntry(IN S_CLASSIFIER_TABLE *pstClassifierTable,
        return PHS_INVALID_TABLE_INDEX;
 }
 
-UINT GetPhsRuleEntry(IN S_CLASSIFIER_TABLE *pstClassifierTable,
-      IN B_UINT32 uiPHSI,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,
-      OUT S_PHS_RULE **ppstPhsRule)
+static UINT GetPhsRuleEntry(IN S_CLASSIFIER_TABLE *pstClassifierTable,
+                           IN B_UINT32 uiPHSI,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,
+                           OUT S_PHS_RULE **ppstPhsRule)
 {
        int  i;
        S_CLASSIFIER_ENTRY *pstClassifierRule = NULL;
@@ -1102,7 +1095,7 @@ UINT CreateClassiferToPHSRuleMapping(IN B_UINT16 uiVcid,
                if(psPhsRule->u8PHSFLength)
                {
                        //update PHSF
-                       OsalMemMove(pstClassifierEntry->pstPhsRule->u8PHSF,
+                       memcpy(pstClassifierEntry->pstPhsRule->u8PHSF,
                            psPhsRule->u8PHSF , MAX_PHS_LENGTHS);
                }
                if(psPhsRule->u8PHSFLength)
@@ -1114,7 +1107,7 @@ UINT CreateClassiferToPHSRuleMapping(IN B_UINT16 uiVcid,
                if(psPhsRule->u8PHSMLength)
                {
                        //update PHSM
-                       OsalMemMove(pstClassifierEntry->pstPhsRule->u8PHSM,
+                       memcpy(pstClassifierEntry->pstPhsRule->u8PHSM,
                            psPhsRule->u8PHSM, MAX_PHS_LENGTHS);
                }
                if(psPhsRule->u8PHSMLength)
@@ -1147,7 +1140,7 @@ UINT CreateClassiferToPHSRuleMapping(IN B_UINT16 uiVcid,
        return uiStatus;
 }
 
-UINT CreateClassifierPHSRule(IN B_UINT16  uiClsId,
+static UINT CreateClassifierPHSRule(IN B_UINT16  uiClsId,
     S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,
     E_CLASSIFIER_ENTRY_CONTEXT eClsContext,B_UINT8 u8AssociatedPHSI)
 {
@@ -1234,8 +1227,7 @@ UINT CreateClassifierPHSRule(IN B_UINT16  uiClsId,
        {
                if(psClassifierRules->pstPhsRule == NULL)
                {
-                       psClassifierRules->pstPhsRule = (S_PHS_RULE*)OsalMemAlloc
-                (sizeof(S_PHS_RULE),PHS_MEM_TAG);
+                       psClassifierRules->pstPhsRule = kmalloc(sizeof(S_PHS_RULE),GFP_KERNEL);
 
           if(NULL == psClassifierRules->pstPhsRule)
                                return ERR_PHSRULE_MEMALLOC_FAIL;
@@ -1247,7 +1239,7 @@ UINT CreateClassifierPHSRule(IN B_UINT16  uiClsId,
                psClassifierRules->bUnclassifiedPHSRule = psPhsRule->bUnclassifiedPHSRule;
 
         /* Update The PHS rule */
-               OsalMemMove(psClassifierRules->pstPhsRule,
+               memcpy(psClassifierRules->pstPhsRule,
                    psPhsRule, sizeof(S_PHS_RULE));
        }
        else
@@ -1259,7 +1251,7 @@ UINT CreateClassifierPHSRule(IN B_UINT16  uiClsId,
 }
 
 
-UINT UpdateClassifierPHSRule(IN B_UINT16  uiClsId,
+static UINT UpdateClassifierPHSRule(IN B_UINT16  uiClsId,
       IN S_CLASSIFIER_ENTRY *pstClassifierEntry,
       S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,
       B_UINT8 u8AssociatedPHSI)
@@ -1289,13 +1281,13 @@ UINT UpdateClassifierPHSRule(IN B_UINT16  uiClsId,
                //Step 2.a PHS Rule Does Not Exist .Create New PHS Rule for uiClsId
                if(FALSE == bPHSRuleOrphaned)
                {
-                       pstClassifierEntry->pstPhsRule = (S_PHS_RULE*)OsalMemAlloc(sizeof(S_PHS_RULE),PHS_MEM_TAG);
+                       pstClassifierEntry->pstPhsRule = kmalloc(sizeof(S_PHS_RULE), GFP_KERNEL);
                        if(NULL == pstClassifierEntry->pstPhsRule)
                        {
                                return ERR_PHSRULE_MEMALLOC_FAIL;
                        }
                }
-               OsalMemMove(pstClassifierEntry->pstPhsRule, psPhsRule, sizeof(S_PHS_RULE));
+               memcpy(pstClassifierEntry->pstPhsRule, psPhsRule, sizeof(S_PHS_RULE));
 
        }
        else
@@ -1304,14 +1296,8 @@ UINT UpdateClassifierPHSRule(IN B_UINT16  uiClsId,
                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nTying Classifier to Existing PHS Rule");
                if(bPHSRuleOrphaned)
                {
-                   if(pstClassifierEntry->pstPhsRule)
-                   {
-                       //Just Free the PHS Rule as Ref Count is Zero
-                       OsalMemFree(pstClassifierEntry->pstPhsRule,sizeof(S_PHS_RULE));
+                       kfree(pstClassifierEntry->pstPhsRule);
                        pstClassifierEntry->pstPhsRule = NULL;
-
-                   }
-
                }
                pstClassifierEntry->pstPhsRule = pstAddPhsRule;
 
@@ -1326,7 +1312,7 @@ UINT UpdateClassifierPHSRule(IN B_UINT16  uiClsId,
 
 }
 
-BOOLEAN DerefPhsRule(IN B_UINT16  uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable,S_PHS_RULE *pstPhsRule)
+static BOOLEAN DerefPhsRule(IN B_UINT16  uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable,S_PHS_RULE *pstPhsRule)
 {
        if(pstPhsRule==NULL)
                return FALSE;
@@ -1345,22 +1331,6 @@ BOOLEAN DerefPhsRule(IN B_UINT16  uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable
        }
 }
 
-static void DumpBuffer(PVOID BuffVAddress, int xferSize)
-{
-       int i;
-       int iPrintLength;
-       PUCHAR temp=(PUCHAR)BuffVAddress;
-    PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
-       iPrintLength=(xferSize<32?xferSize:32);
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\n");
-
-       for (i=0;i < iPrintLength;i++) {
-                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "%x|",temp[i]);
-       }
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\n");
-}
-
-
 void DumpPhsRules(PPHS_DEVICE_EXTENSION pDeviceExtension)
 {
        int i,j,k,l;
@@ -1520,8 +1490,8 @@ int phs_decompress(unsigned char *in_buf,unsigned char *out_buf,
 //     size-The number of bytes copied into the output buffer i.e dynamic fields
 //     0       -If PHS rule is NULL.If PHSV field is not set.If the verification fails.
 //-----------------------------------------------------------------------------
-int phs_compress(S_PHS_RULE  *phs_rule,unsigned char *in_buf
-                                               ,unsigned char *out_buf,UINT *header_size,UINT *new_header_size)
+static int phs_compress(S_PHS_RULE  *phs_rule,unsigned char *in_buf
+                       ,unsigned char *out_buf,UINT *header_size,UINT *new_header_size)
 {
        unsigned char *old_addr = out_buf;
        int supress = 0;
@@ -1581,9 +1551,9 @@ int phs_compress(S_PHS_RULE  *phs_rule,unsigned char *in_buf
 //     0       -Packet has failed the verification.
 //-----------------------------------------------------------------------------
 
- int verify_suppress_phsf(unsigned char *in_buffer,unsigned char *out_buffer,
-                                                               unsigned char *phsf,unsigned char *phsm,unsigned int phss,
-                                                               unsigned int phsv,UINT* new_header_size)
+static int verify_suppress_phsf(unsigned char *in_buffer,unsigned char *out_buffer,
+                               unsigned char *phsf,unsigned char *phsm,unsigned int phss,
+                               unsigned int phsv,UINT* new_header_size)
 {
        unsigned int size=0;
        int bit,i=0;
index bf2b5763252c88733ebfde6e9877b96e456c2a28..0dd05a7c55d962e16886a49e05e9a8b8fe77a5d3 100644 (file)
@@ -27,19 +27,6 @@ void DumpPhsRules(PPHS_DEVICE_EXTENSION pDeviceExtension);
 
 int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension,PMINI_ADAPTER Adapter);
 
-void free_phs_serviceflow_rules(S_SERVICEFLOW_TABLE *psServiceFlowRulesTable);
-
-int phs_compress(S_PHS_RULE   *phs_members,unsigned char *in_buf,
-                                               unsigned char *out_buf,unsigned int *header_size,UINT *new_header_size );
-
-
-int verify_suppress_phsf(unsigned char *in_buffer,unsigned char *out_buffer,
-                                                               unsigned char *phsf,unsigned char *phsm,unsigned int phss,unsigned int phsv,UINT *new_header_size );
-
-int phs_decompress(unsigned char *in_buf,unsigned char *out_buf,\
-                                                 S_PHS_RULE   *phs_rules,UINT *header_size);
-
-
 int PhsCleanup(PPHS_DEVICE_EXTENSION pPHSDeviceExt);
 
 //Utility Functions
@@ -52,42 +39,10 @@ ULONG PhsDeleteClassifierRule(void* pvContext, B_UINT16 uiVcid ,B_UINT16  uiClsI
 ULONG PhsDeleteSFRules(void* pvContext,B_UINT16 uiVcid) ;
 
 
-ULONG PhsCompress(void* pvContext,
-                                 B_UINT16 uiVcid,
-                                 B_UINT16 uiClsId,
-                                 void *pvInputBuffer,
-                                 void *pvOutputBuffer,
-                                 UINT *pOldHeaderSize,
-                                 UINT *pNewHeaderSize );
-
-ULONG PhsDeCompress(void* pvContext,
-                                 B_UINT16 uiVcid,
-                                 void *pvInputBuffer,
-                                 void *pvOutputBuffer,
-                                 UINT *pInHeaderSize,
-                                 UINT *pOutHeaderSize);
-
-
 BOOLEAN ValidatePHSRule(S_PHS_RULE *psPhsRule);
 
-BOOLEAN ValidatePHSRuleComplete(S_PHS_RULE *psPhsRule);
-
 UINT GetServiceFlowEntry(S_SERVICEFLOW_TABLE *psServiceFlowTable,B_UINT16 uiVcid,S_SERVICEFLOW_ENTRY **ppstServiceFlowEntry);
 
-UINT GetClassifierEntry(S_CLASSIFIER_TABLE *pstClassifierTable,B_UINT32 uiClsid,E_CLASSIFIER_ENTRY_CONTEXT eClsContext, S_CLASSIFIER_ENTRY **ppstClassifierEntry);
-
-UINT GetPhsRuleEntry(S_CLASSIFIER_TABLE *pstClassifierTable,B_UINT32 uiPHSI,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,S_PHS_RULE **ppstPhsRule);
-
-
-UINT CreateSFToClassifierRuleMapping(B_UINT16 uiVcid,B_UINT16  uiClsId,S_SERVICEFLOW_TABLE *psServiceFlowTable,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI);
-
-UINT CreateClassiferToPHSRuleMapping(B_UINT16 uiVcid,B_UINT16  uiClsId,S_SERVICEFLOW_ENTRY *pstServiceFlowEntry,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI);
-
-UINT CreateClassifierPHSRule(B_UINT16  uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,E_CLASSIFIER_ENTRY_CONTEXT eClsContext,B_UINT8 u8AssociatedPHSI);
-
-UINT UpdateClassifierPHSRule(B_UINT16  uiClsId,S_CLASSIFIER_ENTRY *pstClassifierEntry,S_CLASSIFIER_TABLE *psaClassifiertable ,S_PHS_RULE *psPhsRule,B_UINT8 u8AssociatedPHSI);
-
-BOOLEAN DerefPhsRule(B_UINT16  uiClsId,S_CLASSIFIER_TABLE *psaClassifiertable,S_PHS_RULE *pstPhsRule);
 
 void DumpPhsRules(PPHS_DEVICE_EXTENSION pDeviceExtension);
 
index 00f1cc12356aa02bd399ea6b180f950e003605d5..b8a4009bdf0cb74568ce20321cdc92db078b4a27 100644 (file)
@@ -85,10 +85,10 @@ typedef struct _ETH_CS_ETH2_FRAME
        ETH_HEADER_STRUC EThHdr;
 } __attribute__((packed)) ETH_CS_ETH2_FRAME;
 
+#define ETHERNET_FRAMETYPE_IPV4                ntohs(0x0800)
+#define ETHERNET_FRAMETYPE_IPV6        ntohs(0x86dd)
+#define ETHERNET_FRAMETYPE_802QVLAN    ntohs(0x8100)
 
-#define ETHERNET_FRAMETYPE_IPV4 ntohs(0x0800)
-#define ETHERNET_FRAMETYPE_IPV6 ntohs(0x86dd)
-#define ETHERNET_FRAMETYPE_802QVLAN 0x8100
 //Per SF CS Specification Encodings
 typedef enum _E_SERVICEFLOW_CS_SPEC_
 {
index 70ec8bcafd1e9ddf4b3bce842709f94f49145455..b80b806c90a3c70bb3c03041adf052ec2a4f7032 100644 (file)
@@ -1,23 +1,12 @@
 #ifndef _PROTOTYPES_H_
 #define _PROTOTYPES_H_
 
-int BcmFileDownload(PMINI_ADAPTER Adapter,/**< Logical Adapter */
-                        char *path,     /**< path to image file */
-                        unsigned int loc    /**< Download Address on the chip*/
-                        );
 VOID LinkControlResponseMessage(PMINI_ADAPTER Adapter, PUCHAR pucBuffer);
 
 VOID StatisticsResponse(PMINI_ADAPTER Adapter,PVOID pvBuffer);
 
 VOID IdleModeResponse(PMINI_ADAPTER Adapter,PUINT puiBuffer);
 
-void bcm_kfree_skb(struct sk_buff *skb);
-VOID bcm_kfree(VOID *ptr);
-
-
-VOID handle_rx_control_packet(PMINI_ADAPTER Adapter,   /**<Pointer to the Adapter structure*/
-                                                               struct sk_buff *skb);                           /**<Pointer to the socket buffer*/
-
 int control_packet_handler     (PMINI_ADAPTER Adapter);
 
 VOID DeleteAllClassifiersForSF(PMINI_ADAPTER Adapter,UINT uiSearchRuleIndex);
@@ -38,25 +27,16 @@ VOID SortClassifiers(PMINI_ADAPTER Adapter);
 
 VOID flush_all_queues(PMINI_ADAPTER Adapter);
 
-USHORT IpVersion4(PMINI_ADAPTER Adapter, /**< Pointer to the driver control structure */
-                                       struct iphdr *iphd, /**<Pointer to the IP Hdr of the packet*/
-                                       S_CLASSIFIER_RULE *pstClassifierRule );
-
-VOID PruneQueue(PMINI_ADAPTER Adapter,/**<Pointer to the driver control structure*/
-                                       INT iIndex/**<Queue Index*/
-                                       );
-
 VOID PruneQueueAllSF(PMINI_ADAPTER Adapter);
 
 INT SearchSfid(PMINI_ADAPTER Adapter,UINT uiSfid);
 
-USHORT GetPacketQueueIndex(PMINI_ADAPTER Adapter, /**<Pointer to the driver control structure */
-                                                               struct sk_buff* Packet /**< Pointer to the Packet to be sent*/
-                                                               );
+USHORT ClassifyPacket(PMINI_ADAPTER Adapter,struct sk_buff* skb);
+
+BOOLEAN MatchSrcPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushSrcPort);
+BOOLEAN MatchDestPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushSrcPort);
+BOOLEAN MatchProtocol(S_CLASSIFIER_RULE *pstClassifierRule,UCHAR ucProtocol);
 
-VOID
-reply_to_arp_request(struct sk_buff *skb  /**<sk_buff of ARP request*/
-                                               );
 
 INT SetupNextSend(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
                                        struct sk_buff *Packet, /**<data buffer*/
@@ -70,11 +50,9 @@ INT SendControlPacket(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
                                                        char *pControlPacket/**<Control Packet*/
                                                        );
 
-INT bcm_transmit(struct sk_buff *skb,          /**< skb */
-                                       struct net_device *dev  /**< net device pointer */
-                                       );
 
 int register_networkdev(PMINI_ADAPTER Adapter);
+void unregister_networkdev(PMINI_ADAPTER Adapter);
 
 INT AllocAdapterDsxBuffer(PMINI_ADAPTER Adapter);
 
@@ -82,8 +60,6 @@ VOID AdapterFree(PMINI_ADAPTER Adapter);
 
 INT FreeAdapterDsxBuffer(PMINI_ADAPTER Adapter);
 
-int create_worker_threads(PMINI_ADAPTER psAdapter);
-
 int tx_pkt_handler(PMINI_ADAPTER Adapter);
 
 int  reset_card_proc(PMINI_ADAPTER Adapter );
@@ -92,7 +68,6 @@ int run_card_proc(PMINI_ADAPTER Adapter );
 
 int InitCardAndDownloadFirmware(PMINI_ADAPTER ps_adapter);
 
-int bcm_parse_target_params(PMINI_ADAPTER Adapter);
 
 INT ReadMacAddressFromNVM(PMINI_ADAPTER Adapter);
 
@@ -110,26 +85,15 @@ int rdmalt (PMINI_ADAPTER Adapter, UINT uiAddress, PUINT pucBuff, size_t sSize);
 
 int get_dsx_sf_data_to_application(PMINI_ADAPTER Adapter, UINT uiSFId, void __user * user_buffer);
 
-void SendLinkDown(PMINI_ADAPTER Adapter);
-
 void SendIdleModeResponse(PMINI_ADAPTER Adapter);
 
-void HandleShutDownModeRequest(PMINI_ADAPTER Adapter,PUCHAR pucBuffer);
-
-int  ProcessGetHostMibs(PMINI_ADAPTER Adapter, PVOID ioBuffer,
-       ULONG inputBufferLength);
 
-int GetDroppedAppCntrlPktMibs(PVOID ioBuffer, PPER_TARANG_DATA pTarang);
+int  ProcessGetHostMibs(PMINI_ADAPTER Adapter, S_MIBS_HOST_STATS_MIBS *buf);
+void GetDroppedAppCntrlPktMibs(S_MIBS_HOST_STATS_MIBS *ioBuffer, PPER_TARANG_DATA pTarang);
 void beceem_parse_target_struct(PMINI_ADAPTER Adapter);
 
-void doPowerAutoCorrection(PMINI_ADAPTER psAdapter);
-
 int bcm_ioctl_fw_download(PMINI_ADAPTER Adapter, FIRMWARE_INFO *psFwInfo);
 
-void bcm_unregister_networkdev(PMINI_ADAPTER Adapter);
-
-int SearchVcid(PMINI_ADAPTER Adapter,unsigned short usVcid);
-
 void CopyMIBSExtendedSFParameters(PMINI_ADAPTER Adapter,
                CServiceFlowParamSI *psfLocalSet, UINT uiSearchRuleIndex);
 
@@ -149,7 +113,6 @@ void update_per_sf_desc_cnts( PMINI_ADAPTER Adapter);
 
 void ClearTargetDSXBuffer(PMINI_ADAPTER Adapter,B_UINT16 TID,BOOLEAN bFreeAll);
 
-void beceem_protocol_reset (PMINI_ADAPTER Adapter);
 
 void flush_queue(PMINI_ADAPTER Adapter, UINT iQIndex);
 
@@ -164,31 +127,11 @@ INT BeceemEEPROMBulkRead(
        UINT uiNumBytes);
 
 
-INT BeceemFlashBulkRead(
-       PMINI_ADAPTER Adapter,
-       PUINT pBuffer,
-       UINT uiOffset,
-       UINT uiNumBytes);
-
-UINT BcmGetEEPROMSize(PMINI_ADAPTER Adapter);
 
 INT WriteBeceemEEPROM(PMINI_ADAPTER Adapter,UINT uiEEPROMOffset, UINT uiData);
 
-UINT BcmGetFlashSize(PMINI_ADAPTER Adapter);
-
-UINT BcmGetFlashSectorSize(PMINI_ADAPTER Adapter, UINT FlashSectorSizeSig, UINT FlashSectorSize);
-
-INT BeceemFlashBulkWrite(
-       PMINI_ADAPTER Adapter,
-       PUINT pBuffer,
-       UINT uiOffset,
-       UINT uiNumBytes,
-       BOOLEAN bVerify);
-
 INT PropagateCalParamsFromFlashToMemory(PMINI_ADAPTER Adapter);
 
-INT PropagateCalParamsFromEEPROMToMemory(PMINI_ADAPTER Adapter);
-
 
 INT BeceemEEPROMBulkWrite(
        PMINI_ADAPTER Adapter,
@@ -198,11 +141,8 @@ INT BeceemEEPROMBulkWrite(
        BOOLEAN bVerify);
 
 
-INT ReadBeceemEEPROMBulk(PMINI_ADAPTER Adapter,UINT dwAddress, UINT *pdwData, UINT dwNumData);
-
 INT ReadBeceemEEPROM(PMINI_ADAPTER Adapter,UINT dwAddress, UINT *pdwData);
 
-NVM_TYPE BcmGetNvmType(PMINI_ADAPTER Adapter);
 
 INT BeceemNVMRead(
        PMINI_ADAPTER Adapter,
@@ -217,24 +157,12 @@ INT BeceemNVMWrite(
        UINT uiNumBytes,
        BOOLEAN bVerify);
 
-INT BcmUpdateSectorSize(PMINI_ADAPTER Adapter,UINT uiSectorSize);
 
 INT BcmInitNVM(PMINI_ADAPTER Adapter);
 
-INT BcmGetNvmSize(PMINI_ADAPTER Adapter);
-
-INT IsSectionExistInVendorInfo(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section);
-
-VOID BcmValidateNvmType(PMINI_ADAPTER Adapter);
-
-VOID ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter);
+INT BcmUpdateSectorSize(PMINI_ADAPTER Adapter,UINT uiSectorSize);
+BOOLEAN IsSectionExistInFlash(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section);
 
-INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter);
-INT ReadDSDHeader(PMINI_ADAPTER Adapter, PDSD_HEADER psDSDHeader, FLASH2X_SECTION_VAL dsd);
-INT BcmGetActiveDSD(PMINI_ADAPTER Adapter);
-INT ReadISOHeader(PMINI_ADAPTER Adapter, PISO_HEADER psISOHeader, FLASH2X_SECTION_VAL IsoImage);
-INT BcmGetActiveISO(PMINI_ADAPTER Adapter);
-B_UINT8 IsOffsetWritable(PMINI_ADAPTER Adapter, UINT uiOffset);
 INT BcmGetFlash2xSectionalBitMap(PMINI_ADAPTER Adapter, PFLASH2X_BITMAP psFlash2xBitMap);
 
 INT BcmFlash2xBulkWrite(
@@ -251,7 +179,6 @@ INT BcmFlash2xBulkRead(
        FLASH2X_SECTION_VAL eFlashSectionVal,
        UINT uiOffsetWithinSectionVal,
        UINT uiNumBytes);
-INT BcmGetSectionValEndOffset(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlashSectionVal);
 
 INT BcmGetSectionValStartOffset(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlashSectionVal);
 
@@ -264,34 +191,13 @@ INT BcmFlash2xCorruptSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSect
 INT BcmFlash2xWriteSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlashSectionVal);
 INT    validateFlash2xReadWrite(PMINI_ADAPTER Adapter, PFLASH2X_READWRITE psFlash2xReadWrite);
 INT IsFlash2x(PMINI_ADAPTER Adapter);
-INT GetFlashBaseAddr(PMINI_ADAPTER Adapter);
-INT SaveHeaderIfPresent(PMINI_ADAPTER Adapter, PUCHAR pBuff, UINT uiSectAlignAddr);
 INT    BcmCopySection(PMINI_ADAPTER Adapter,
                                                FLASH2X_SECTION_VAL SrcSection,
                                                FLASH2X_SECTION_VAL DstSection,
                                                UINT offset,
                                                UINT numOfBytes);
 
-INT BcmDoChipSelect(PMINI_ADAPTER Adapter, UINT offset);
-INT BcmMakeFlashCSActive(PMINI_ADAPTER Adapter, UINT offset);
-INT ReadDSDSignature(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL dsd);
-INT ReadDSDPriority(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL dsd);
-FLASH2X_SECTION_VAL getHighestPriDSD(PMINI_ADAPTER Adapter);
-INT ReadISOSignature(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL iso);
-INT ReadISOPriority(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL iso);
-FLASH2X_SECTION_VAL getHighestPriISO(PMINI_ADAPTER Adapter);
-INT WriteToFlashWithoutSectorErase(PMINI_ADAPTER Adapter,
-                                                                               PUINT pBuff,
-                                                                               FLASH2X_SECTION_VAL eFlash2xSectionVal,
-                                                                               UINT uiOffset,
-                                                                               UINT uiNumBytes
-                                                                               );
-
-//UINT getNumOfSubSectionWithWRPermisson(PMINI_ADAPTER Adapter, SECTION_TYPE secType);
-BOOLEAN IsSectionExistInFlash(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section);
-INT IsSectionWritable(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL Section);
-INT CorruptDSDSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal);
-INT CorruptISOSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal);
+
 BOOLEAN IsNonCDLessDevice(PMINI_ADAPTER Adapter);
 
 
@@ -300,7 +206,6 @@ VOID OverrideServiceFlowParams(PMINI_ADAPTER Adapter,PUINT puiBuffer);
 int wrmaltWithLock (PMINI_ADAPTER Adapter, UINT uiAddress, PUINT pucBuff, size_t sSize);
 int rdmaltWithLock (PMINI_ADAPTER Adapter, UINT uiAddress, PUINT pucBuff, size_t sSize);
 
-int rdmWithLock(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t size);
 int wrmWithLock(PMINI_ADAPTER Adapter, UINT uiAddress, PCHAR pucBuff, size_t size);
 INT buffDnldVerify(PMINI_ADAPTER Adapter, unsigned char *mappedbuffer, unsigned int u32FirmwareLength,
                unsigned long u32StartingAddress);
@@ -309,11 +214,6 @@ INT buffDnldVerify(PMINI_ADAPTER Adapter, unsigned char *mappedbuffer, unsigned
 VOID putUsbSuspend(struct work_struct *work);
 BOOLEAN IsReqGpioIsLedInNVM(PMINI_ADAPTER Adapter, UINT gpios);
 
-#ifdef BCM_SHM_INTERFACE
-INT beceem_virtual_device_init(void);
-VOID virtual_mail_box_interrupt(void);
-INT beceem_virtual_device_exit(void);
-#endif
 
 #endif
 
index 75b2b879633f6f845632ebf911d2b8e894088ef2..8ce4536e6e289549f067cd1b594263483e4f496b 100644 (file)
@@ -4,15 +4,14 @@ This file contains the routines related to Quality of Service.
 */
 #include "headers.h"
 
-BOOLEAN MatchSrcIpAddress(S_CLASSIFIER_RULE *pstClassifierRule,ULONG ulSrcIP);
-BOOLEAN MatchTos(S_CLASSIFIER_RULE *pstClassifierRule,UCHAR ucTypeOfService);
-BOOLEAN MatchSrcPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushSrcPort);
-BOOLEAN MatchDestPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushDestPort);
-BOOLEAN MatchProtocol(S_CLASSIFIER_RULE *pstClassifierRule,UCHAR ucProtocol);
-BOOLEAN MatchDestIpAddress(S_CLASSIFIER_RULE *pstClassifierRule,ULONG ulDestIP);
-USHORT ClassifyPacket(PMINI_ADAPTER Adapter,struct sk_buff* skb);
-void EThCSGetPktInfo(PMINI_ADAPTER Adapter,PVOID pvEthPayload,PS_ETHCS_PKT_INFO pstEthCsPktInfo);
-BOOLEAN EThCSClassifyPkt(PMINI_ADAPTER Adapter,struct sk_buff* skb,PS_ETHCS_PKT_INFO pstEthCsPktInfo,S_CLASSIFIER_RULE *pstClassifierRule, B_UINT8 EthCSCupport);
+static void EThCSGetPktInfo(PMINI_ADAPTER Adapter,PVOID pvEthPayload,PS_ETHCS_PKT_INFO pstEthCsPktInfo);
+static BOOLEAN EThCSClassifyPkt(PMINI_ADAPTER Adapter,struct sk_buff* skb,PS_ETHCS_PKT_INFO pstEthCsPktInfo,S_CLASSIFIER_RULE *pstClassifierRule, B_UINT8 EthCSCupport);
+
+static USHORT  IpVersion4(PMINI_ADAPTER Adapter, struct iphdr *iphd,
+                          S_CLASSIFIER_RULE *pstClassifierRule );
+
+static VOID PruneQueue(PMINI_ADAPTER Adapter, INT iIndex);
+
 
 /*******************************************************************
 * Function    - MatchSrcIpAddress()
@@ -205,11 +204,10 @@ BOOLEAN MatchDestPort(S_CLASSIFIER_RULE *pstClassifierRule,USHORT ushDestPort)
 Compares IPV4 Ip address and port number
 @return Queue Index.
 */
-USHORT IpVersion4(PMINI_ADAPTER Adapter, /**< Pointer to the driver control structure */
-                                       struct iphdr *iphd, /**<Pointer to the IP Hdr of the packet*/
-                                       S_CLASSIFIER_RULE *pstClassifierRule )
+static USHORT  IpVersion4(PMINI_ADAPTER Adapter,
+                          struct iphdr *iphd,
+                          S_CLASSIFIER_RULE *pstClassifierRule )
 {
-       //IPHeaderFormat                *pIpHeader=NULL;
        xporthdr                *xprt_hdr=NULL;
        BOOLEAN bClassificationSucceed=FALSE;
 
@@ -261,15 +259,6 @@ USHORT     IpVersion4(PMINI_ADAPTER Adapter, /**< Pointer to the driver control stru
                //if protocol is not TCP or UDP then no need of comparing source port and destination port
                if(iphd->protocol!=TCP && iphd->protocol!=UDP)
                        break;
-#if 0
-               //check if memory is available of src and Dest port
-               if(ETH_AND_IP_HEADER_LEN + L4_SRC_PORT_LEN + L4_DEST_PORT_LEN > Packet->len)
-               {
-                       //This is not an erroneous condition and pkt will be checked for next classification.
-                       bClassificationSucceed = FALSE;
-                       break;
-               }
-#endif
                //******************Checking Transport Layer Header field if present *****************//
                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Source Port %04x",
                        (iphd->protocol==UDP)?xprt_hdr->uhdr.source:xprt_hdr->thdr.source);
@@ -312,29 +301,6 @@ USHORT     IpVersion4(PMINI_ADAPTER Adapter, /**< Pointer to the driver control stru
 
        return bClassificationSucceed;
 }
-/**
-@ingroup tx_functions
-@return  Queue Index based on priority.
-*/
-USHORT GetPacketQueueIndex(PMINI_ADAPTER Adapter, /**<Pointer to the driver control structure */
-                                                               struct sk_buff* Packet /**< Pointer to the Packet to be sent*/
-                                                               )
-{
-       USHORT                  usIndex=-1;
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, QUEUE_INDEX, DBG_LVL_ALL, "=====>");
-
-       if(NULL==Adapter || NULL==Packet)
-       {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, QUEUE_INDEX, DBG_LVL_ALL, "Got NULL Values<======");
-               return -1;
-       }
-
-       usIndex = ClassifyPacket(Adapter,Packet);
-
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, QUEUE_INDEX, DBG_LVL_ALL, "Got Queue Index %x",usIndex);
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, QUEUE_INDEX, DBG_LVL_ALL, "GetPacketQueueIndex <==============");
-       return usIndex;
-}
 
 VOID PruneQueueAllSF(PMINI_ADAPTER Adapter)
 {
@@ -357,23 +323,21 @@ is less than number of bytes in the queue. If so -
 drops packets from the Head till the number of bytes is
 less than or equal to max queue size for the queue.
 */
-VOID PruneQueue(PMINI_ADAPTER Adapter,/**<Pointer to the driver control structure*/
-                                       INT iIndex/**<Queue Index*/
-                                       )
+static VOID PruneQueue(PMINI_ADAPTER Adapter, INT iIndex)
 {
        struct sk_buff* PacketToDrop=NULL;
-       struct net_device_stats*  netstats=NULL;
+       struct net_device_stats *netstats;
 
        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "=====> Index %d",iIndex);
 
        if(iIndex == HiPriority)
-               return;
+               return;
 
        if(!Adapter || (iIndex < 0) || (iIndex > HiPriority))
                return;
 
        /* To Store the netdevice statistic */
-       netstats = &((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats;
+       netstats = &Adapter->dev->stats;
 
        spin_lock_bh(&Adapter->PackInfo[iIndex].SFQueueLock);
 
@@ -395,9 +359,13 @@ VOID PruneQueue(PMINI_ADAPTER Adapter,/**<Pointer to the driver control structur
 
                if(PacketToDrop)
                {
-                       if(netstats)
-                               netstats->tx_dropped++;
-                       atomic_inc(&Adapter->TxDroppedPacketCount);
+                       struct netdev_queue *txq = netdev_get_tx_queue(Adapter->dev, iIndex);
+                       if (netif_msg_tx_err(Adapter))
+                               pr_info(PFX "%s: tx queue %d overlimit\n", 
+                                       Adapter->dev->name, iIndex);
+
+                       txq->tx_dropped++;
+
                        DEQUEUEPACKET(Adapter->PackInfo[iIndex].FirstTxQueue,
                                                Adapter->PackInfo[iIndex].LastTxQueue);
                        /// update current bytes and packets count
@@ -407,7 +375,7 @@ VOID PruneQueue(PMINI_ADAPTER Adapter,/**<Pointer to the driver control structur
                        /// update dropped bytes and packets counts
                        Adapter->PackInfo[iIndex].uiDroppedCountBytes += PacketToDrop->len;
                        Adapter->PackInfo[iIndex].uiDroppedCountPackets++;
-                       bcm_kfree_skb(PacketToDrop);
+                       dev_kfree_skb(PacketToDrop);
 
                }
 
@@ -416,7 +384,6 @@ VOID PruneQueue(PMINI_ADAPTER Adapter,/**<Pointer to the driver control structur
                        Adapter->PackInfo[iIndex].uiDroppedCountPackets);
 
                atomic_dec(&Adapter->TotalPacketCount);
-               Adapter->bcm_jiffies = jiffies;
        }
 
        spin_unlock_bh(&Adapter->PackInfo[iIndex].SFQueueLock);
@@ -430,16 +397,15 @@ VOID flush_all_queues(PMINI_ADAPTER Adapter)
 {
        INT             iQIndex;
        UINT    uiTotalPacketLength;
-       struct sk_buff*                         PacketToDrop=NULL;
-       struct net_device_stats*        netstats=NULL;
+       struct sk_buff*                 PacketToDrop=NULL;
 
        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "=====>");
-       /* To Store the netdevice statistic */
-       netstats = &((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats;
 
 //     down(&Adapter->data_packet_queue_lock);
        for(iQIndex=LowPriority; iQIndex<HiPriority; iQIndex++)
        {
+               struct netdev_queue *txq = netdev_get_tx_queue(Adapter->dev, iQIndex);
+
                spin_lock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock);
                while(Adapter->PackInfo[iQIndex].FirstTxQueue)
                {
@@ -447,8 +413,7 @@ VOID flush_all_queues(PMINI_ADAPTER Adapter)
                        if(PacketToDrop)
                        {
                                uiTotalPacketLength = PacketToDrop->len;
-                               netstats->tx_dropped++;
-                               atomic_inc(&Adapter->TxDroppedPacketCount);
+                               txq->tx_dropped++;
                        }
                        else
                                uiTotalPacketLength = 0;
@@ -457,7 +422,7 @@ VOID flush_all_queues(PMINI_ADAPTER Adapter)
                                                Adapter->PackInfo[iQIndex].LastTxQueue);
 
                        /* Free the skb */
-                       bcm_kfree_skb(PacketToDrop);
+                       dev_kfree_skb(PacketToDrop);
 
                        /// update current bytes and packets count
                        Adapter->PackInfo[iQIndex].uiCurrentBytesOnHost -= uiTotalPacketLength;
@@ -559,12 +524,6 @@ USHORT ClassifyPacket(PMINI_ADAPTER Adapter,struct sk_buff* skb)
 
        for(uiLoopIndex = MAX_CLASSIFIERS - 1; uiLoopIndex >= 0; uiLoopIndex--)
        {
-               if (Adapter->device_removed)
-               {
-                       bClassificationSucceed = FALSE;
-                       break;
-               }
-
                if(bClassificationSucceed)
                        break;
                //Iterate through all classifiers which are already in order of priority
@@ -810,7 +769,10 @@ static BOOLEAN EthCSMatchVLANRules(S_CLASSIFIER_RULE *pstClassifierRule,struct s
 }
 
 
-BOOLEAN EThCSClassifyPkt(PMINI_ADAPTER Adapter,struct sk_buff* skb,PS_ETHCS_PKT_INFO pstEthCsPktInfo,S_CLASSIFIER_RULE *pstClassifierRule, B_UINT8 EthCSCupport)
+static BOOLEAN EThCSClassifyPkt(PMINI_ADAPTER Adapter,struct sk_buff* skb,
+                               PS_ETHCS_PKT_INFO pstEthCsPktInfo,
+                               S_CLASSIFIER_RULE *pstClassifierRule,
+                               B_UINT8 EthCSCupport)
 {
        BOOLEAN bClassificationSucceed = FALSE;
        bClassificationSucceed = EthCSMatchSrcMACAddress(pstClassifierRule,((ETH_HEADER_STRUC *)(skb->data))->au8SourceAddress);
@@ -840,9 +802,11 @@ BOOLEAN EThCSClassifyPkt(PMINI_ADAPTER Adapter,struct sk_buff* skb,PS_ETHCS_PKT_
        return bClassificationSucceed;
 }
 
-void EThCSGetPktInfo(PMINI_ADAPTER Adapter,PVOID pvEthPayload,PS_ETHCS_PKT_INFO pstEthCsPktInfo)
+static void EThCSGetPktInfo(PMINI_ADAPTER Adapter,PVOID pvEthPayload,
+                           PS_ETHCS_PKT_INFO pstEthCsPktInfo)
 {
        USHORT u16Etype = ntohs(((ETH_HEADER_STRUC*)pvEthPayload)->u16Etype);
+
        BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL,  "EthCSGetPktInfo : Eth Hdr Type : %X\n",u16Etype);
        if(u16Etype > 0x5dc)
        {
index 366634be5fe1d4cf2065f57d480230dbc1a754d9..cd3e9f2ed87a605bc6a3ec46fcb3d8d5bd1723ac 100644 (file)
@@ -1,15 +1,22 @@
+This driver is barely functional in its current state.
+
+BIG:
+       - existing API is (/dev/tarang) should be replaced
+         Is it possible to use same API as Intel Wimax stack and
+         have same user level components.
+       - Qos and queue model is non-standard and inflexible.
+         Use existing TC Qos?
+
 TODO:
+       - support more than one board - eliminate global variables
+       - remove developer debug BCM_DEBUG() macros
+         add a limited number of messages through netif_msg()
        - fix non-standard kernel style
-       - sparse warnings
        - checkpatch warnings
-       - remove compatiablity code for older kernels
-       - remove #ifdef's
-       - fix bogus device nameing and reference counting (see bcm_notify_event)
-       - fix use of file I/O to load config
-       - request firmware
-       - update to current network device API
-       - merge some files together
+       - use request firmware
+       - fix use of file I/O to load config with better API
+       - merge some files together?
        - cleanup/eliminate debug messages
 
-       - integrate with existing Wimax stack?
+
 
index 12f9e13457db0925420d8eb420ad65dd0399767b..0f7000960d5094d9a68532e97fa528ca3599b1de 100644 (file)
@@ -6,7 +6,7 @@
 digraph transmit1 {
 node[shape=box]
 edge[weight=5;color=red]
-bcm_transmit->reply_to_arp_request[label="ARP"]
+
 bcm_transmit->GetPacketQueueIndex[label="IP Packet"]
 GetPacketQueueIndex->IpVersion4[label="IPV4"]
 GetPacketQueueIndex->IpVersion6[label="IPV6"]
@@ -35,169 +35,16 @@ SendPacketFromQueue->SetupNextSend->bcm_cmd53
 
 #include "headers.h"
 
-/*******************************************************************
-* Function    -        bcm_transmit()
-*
-* Description - This is the main transmit function for our virtual
-*                              interface(veth0). It handles the ARP packets. It
-*                              clones this packet and then Queue it to a suitable
-*                              Queue. Then calls the transmit_packet().
-*
-* Parameter   -         skb - Pointer to the socket buffer structure
-*                               dev - Pointer to the virtual net device structure
-*
-* Returns     -         zero (success) or -ve value (failure)
-*
-*********************************************************************/
-
-INT bcm_transmit(struct sk_buff *skb,          /**< skb */
-                                       struct net_device *dev  /**< net device pointer */
-                                       )
-{
-       PMINI_ADAPTER           Adapter = NULL;
-       USHORT                          qindex=0;
-       struct timeval tv;
-       UINT            pkt_type = 0;
-       UINT            calltransmit = 0;
-
-       BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "\n%s====>\n",__FUNCTION__);
-
-       memset(&tv, 0, sizeof(tv));
-       /* Check for valid parameters */
-       if(skb == NULL || dev==NULL)
-       {
-           BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX,TX_OSAL_DBG, DBG_LVL_ALL, "Got NULL skb or dev\n");
-               return -EINVAL;
-       }
-
-       Adapter = GET_BCM_ADAPTER(dev);
-       if(!Adapter)
-       {
-               BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Got Invalid Adapter\n");
-               return -EINVAL;
-       }
-       if(Adapter->device_removed == TRUE || !Adapter->LinkUpStatus)
-       {
-               if(!netif_queue_stopped(dev)) {
-                               netif_carrier_off(dev);
-                               netif_stop_queue(dev);
-               }
-               return STATUS_FAILURE;
-       }
-       BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Packet size : %d\n", skb->len);
-
-       /*Add Ethernet CS check here*/
-       if(Adapter->TransferMode == IP_PACKET_ONLY_MODE )
-       {
-        pkt_type = ntohs(*(PUSHORT)(skb->data + 12));
-               /* Get the queue index where the packet is to be queued */
-               BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Getting the Queue Index.....");
-
-               qindex = GetPacketQueueIndex(Adapter,skb);
-
-               if((SHORT)INVALID_QUEUE_INDEX==(SHORT)qindex)
-               {
-                       if(pkt_type == ETH_ARP_FRAME)
-                       {
-                               /*
-                               Reply directly to ARP request packet
-                               ARP Spoofing only if NO ETH CS rule matches for it
-                               */
-                               BCM_DEBUG_PRINT (Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ARP OPCODE = %02x",
-
-                (*(PUCHAR)(skb->data + 21)));
-
-                reply_to_arp_request(skb);
-
-                BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX,TX_OSAL_DBG, DBG_LVL_ALL,"After reply_to_arp_request \n");
-
-                       }
-                       else
-                       {
-                BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,
-                       "Invalid queue index, dropping pkt\n");
-
-                               bcm_kfree_skb(skb);
-                       }
-                       return STATUS_SUCCESS;
-        }
-
-               if(Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= SF_MAX_ALLOWED_PACKETS_TO_BACKUP)
-               {
-                       atomic_inc(&Adapter->TxDroppedPacketCount);
-                       bcm_kfree_skb(skb);
-                       return STATUS_SUCCESS;
-               }
-
-               /* Now Enqueue the packet */
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "bcm_transmit Enqueueing the Packet To Queue %d",qindex);
-               spin_lock(&Adapter->PackInfo[qindex].SFQueueLock);
-               Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len;
-               Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++;
-
-               *((B_UINT32 *)skb->cb + SKB_CB_LATENCY_OFFSET ) = jiffies;
-               ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue,
-                         Adapter->PackInfo[qindex].LastTxQueue, skb);
-               atomic_inc(&Adapter->TotalPacketCount);
-               spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock);
-               do_gettimeofday(&tv);
-
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL,"ENQ: \n");
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "Pkt Len = %d, sec: %ld, usec: %ld\n",
-               (skb->len-ETH_HLEN), tv.tv_sec, tv.tv_usec);
-
-#ifdef BCM_SHM_INTERFACE
-               spin_lock(&Adapter->txtransmitlock);
-               if(Adapter->txtransmit_running == 0)
-               {
-                       Adapter->txtransmit_running = 1;
-                       calltransmit = 1;
-               }
-               else
-                       calltransmit = 0;
-
-               spin_unlock(&Adapter->txtransmitlock);
-#endif
-               if(calltransmit == 1)
-                       transmit_packets(Adapter);
-               else
-               {
-                       if(!atomic_read(&Adapter->TxPktAvail))
-                       {
-                               atomic_set(&Adapter->TxPktAvail, 1);
-#ifdef BCM_SHM_INTERFACE
-                               virtual_mail_box_interrupt();
-#endif
-                               wake_up(&Adapter->tx_packet_wait_queue);
-                       }
-               }
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_OSAL_DBG, DBG_LVL_ALL, "<====");
-       }
-       else
-               bcm_kfree_skb(skb);
-
-  return STATUS_SUCCESS;
-}
-
 
 /**
 @ingroup ctrl_pkt_functions
 This function dispatches control packet to the h/w interface
 @return zero(success) or -ve value(failure)
 */
-INT SendControlPacket(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
-                                                       char *pControlPacket/**<Control Packet*/
-                                                       )
+INT SendControlPacket(PMINI_ADAPTER Adapter, char *pControlPacket)
 {
-       PLEADER PLeader = NULL;
-       struct timeval tv;
-       memset(&tv, 0, sizeof(tv));
-
-
-
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "========>");
+       PLEADER PLeader = (PLEADER)pControlPacket;
 
-       PLeader=(PLEADER)pControlPacket;
        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Tx");
        if(!pControlPacket || !Adapter)
        {
@@ -208,12 +55,6 @@ INT SendControlPacket(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
                ((PLeader->PLength-1)/MAX_DEVICE_DESC_SIZE)+1))
     {
        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "NO FREE DESCRIPTORS TO SEND CONTROL PACKET");
-               if(Adapter->bcm_jiffies == 0)
-        {
-               Adapter->bcm_jiffies = jiffies;
-            BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "UPDATED TIME(hex): %lu",
-                               Adapter->bcm_jiffies);
-        }
         return STATUS_FAILURE;
     }
 
@@ -224,76 +65,33 @@ INT SendControlPacket(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Length: %x",PLeader->PLength);
        if(Adapter->device_removed)
                return 0;
-#ifndef BCM_SHM_INTERFACE
-       Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
-                                       pControlPacket, (PLeader->PLength + LEADER_SIZE));
-#else
-       tx_pkts_to_firmware(pControlPacket,(PLeader->PLength + LEADER_SIZE),1);
 
-       if(PLeader->Status==IDLE_MESSAGE)
-       {
-               if(((CONTROL_MESSAGE*)PLeader)->szData[0] == GO_TO_IDLE_MODE_PAYLOAD &&
-               ((CONTROL_MESSAGE*)PLeader)->szData[1] == TARGET_CAN_GO_TO_IDLE_MODE)
-               {
-                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Idle Mode Ack Sent to the Device\n");
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Host Entering into Idle Mode\n");
-                       do_gettimeofday(&tv);
-                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "IdleMode Msg sent to f/w at time :%ld ms", tv.tv_sec *1000 + tv.tv_usec /1000);
-                       if(Adapter->bDoSuspend != TRUE)
-                       {
-                               Adapter->IdleMode = TRUE;
-                               Adapter->bPreparingForLowPowerMode = FALSE ;
-                       }
-               }
-       }
-       if((PLeader->Status == LINK_UP_CONTROL_REQ) &&
-               ((PUCHAR)pControlPacket)[sizeof(LEADER)] == LINK_UP_ACK &&
-               ((PUCHAR)pControlPacket)[sizeof(LEADER)+1] ==
-                                                               LINK_SHUTDOWN_REQ_FROM_FIRMWARE  &&
-               ((PUCHAR)pControlPacket)[sizeof(LEADER)+2] == SHUTDOWN_ACK_FROM_DRIVER)
-       {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Shut Down ACK Sent and Host entering Shut State \n");
-               if(Adapter->bDoSuspend != TRUE)
-               {
-                       Adapter->bShutStatus = TRUE;
-                       Adapter->bPreparingForLowPowerMode = FALSE;
-                       Adapter->bTriedToWakeUpFromlowPowerMode = FALSE;
-               }
+       if (netif_msg_pktdata(Adapter))
+               print_hex_dump(KERN_DEBUG, PFX "tx control: ", DUMP_PREFIX_NONE,
+                              16, 1, pControlPacket, PLeader->PLength + LEADER_SIZE, 0);
 
-       }
-#endif
+       Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
+                                       pControlPacket, (PLeader->PLength + LEADER_SIZE));
 
-       ((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats.tx_packets++;
-       ((PLINUX_DEP_DATA)Adapter->pvOsDepData)->netstats.tx_bytes+=
-                       PLeader->PLength;
        atomic_dec(&Adapter->CurrNumFreeTxDesc);
        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "<=========");
        return STATUS_SUCCESS;
 }
-static LEADER Leader={0};
+
 /**
 @ingroup tx_functions
 This function despatches the IP packets with the given vcid
 to the target via the host h/w interface.
 @return  zero(success) or -ve value(failure)
 */
-INT SetupNextSend(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
-                                       struct sk_buff *Packet, /**<data buffer*/
-                                       USHORT Vcid)                    /**<VCID for this packet*/
+INT SetupNextSend(PMINI_ADAPTER Adapter,  struct sk_buff *Packet, USHORT Vcid)
 {
        int             status=0;
-#ifdef GDMA_INTERFACE
-       int dontfree = 0;
-#endif
        BOOLEAN bHeaderSupressionEnabled = FALSE;
        B_UINT16            uiClassifierRuleID;
-       int QueueIndex = NO_OF_QUEUES + 1;
+       u16     QueueIndex = skb_get_queue_mapping(Packet);
+       LEADER Leader={0};
 
-       if(!Adapter || !Packet)
-       {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Got NULL Adapter or Packet");
-               return -EINVAL;
-       }
        if(Packet->len > MAX_DEVICE_DESC_SIZE)
        {
                status = STATUS_FAILURE;
@@ -302,14 +100,10 @@ INT SetupNextSend(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
 
        /* Get the Classifier Rule ID */
        uiClassifierRuleID = *((UINT32*) (Packet->cb)+SKB_CB_CLASSIFICATION_OFFSET);
-       QueueIndex = SearchVcid( Adapter,Vcid);
-       if(QueueIndex < NO_OF_QUEUES)
-       {
-               bHeaderSupressionEnabled =
-                       Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled;
-               bHeaderSupressionEnabled =
-                       bHeaderSupressionEnabled & Adapter->bPHSEnabled;
-       }
+
+       bHeaderSupressionEnabled = Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled
+               & Adapter->bPHSEnabled;
+
        if(Adapter->device_removed)
                {
                status = STATUS_FAILURE;
@@ -327,15 +121,10 @@ INT SetupNextSend(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
 
        Leader.Vcid     = Vcid;
 
-    if(TCP_ACK == *((UINT32*) (Packet->cb) + SKB_CB_TCPACK_OFFSET ))
-       {
-        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Sending TCP ACK\n");
+       if(TCP_ACK == *((UINT32*) (Packet->cb) + SKB_CB_TCPACK_OFFSET ))
                Leader.Status = LEADER_STATUS_TCP_ACK;
-       }
        else
-       {
                Leader.Status = LEADER_STATUS;
-       }
 
        if(Adapter->PackInfo[QueueIndex].bEthCSSupport)
        {
@@ -351,68 +140,53 @@ INT SetupNextSend(PMINI_ADAPTER Adapter, /**<Logical Adapter*/
                skb_push(Packet, LEADER_SIZE);
                memcpy(Packet->data, &Leader, LEADER_SIZE);
        }
-
        else
        {
                Leader.PLength = Packet->len - ETH_HLEN;
                memcpy((LEADER*)skb_pull(Packet, (ETH_HLEN - LEADER_SIZE)), &Leader, LEADER_SIZE);
        }
 
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Packet->len = %d", Packet->len);
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Vcid = %d", Vcid);
-
-#ifndef BCM_SHM_INTERFACE
        status = Adapter->interface_transmit(Adapter->pvInterfaceAdapter,
                        Packet->data, (Leader.PLength + LEADER_SIZE));
-#else
-       status = tx_pkts_to_firmware(Packet,Packet->len,0);
-#endif
        if(status)
        {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Tx Failed..\n");
+               ++Adapter->dev->stats.tx_errors;
+               if (netif_msg_tx_err(Adapter))
+                       pr_info(PFX "%s: transmit error %d\n", Adapter->dev->name,
+                               status);
        }
        else
        {
+               struct netdev_queue *txq = netdev_get_tx_queue(Adapter->dev, QueueIndex);
                Adapter->PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength;
-               atomic_add(Leader.PLength, &Adapter->GoodTxByteCount);
-               atomic_inc(&Adapter->TxTotalPacketCount);
-#ifdef GDMA_INTERFACE
-    dontfree = 1;
-#endif
-       }
 
-       atomic_dec(&Adapter->CurrNumFreeTxDesc);
-
-errExit:
+               txq->tx_bytes += Leader.PLength;
+               ++txq->tx_packets;
 
-       if(STATUS_SUCCESS == status)
-       {
                Adapter->PackInfo[QueueIndex].uiCurrentTokenCount -= Leader.PLength << 3;
                Adapter->PackInfo[QueueIndex].uiSentBytes += (Packet->len);
                Adapter->PackInfo[QueueIndex].uiSentPackets++;
                Adapter->PackInfo[QueueIndex].NumOfPacketsSent++;
 
                atomic_dec(&Adapter->PackInfo[QueueIndex].uiPerSFTxResourceCount);
-#ifdef BCM_SHM_INTERFACE
-               if(atomic_read(&Adapter->PackInfo[QueueIndex].uiPerSFTxResourceCount) < 0)
-               {
-                       atomic_set(&Adapter->PackInfo[QueueIndex].uiPerSFTxResourceCount, 0);
-               }
-#endif
                Adapter->PackInfo[QueueIndex].uiThisPeriodSentBytes += Leader.PLength;
        }
 
+       atomic_dec(&Adapter->CurrNumFreeTxDesc);
 
-#ifdef GDMA_INTERFACE
-  if(!dontfree){
-       bcm_kfree_skb(Packet);
-  }
-#else
-       bcm_kfree_skb(Packet);
-#endif
+errExit:
+
+       dev_kfree_skb(Packet);
        return status;
 }
 
+static int tx_pending(PMINI_ADAPTER Adapter)
+{
+       return (atomic_read(&Adapter->TxPktAvail)
+               && MINIMUM_PENDING_DESCRIPTORS < atomic_read(&Adapter->CurrNumFreeTxDesc))
+               || Adapter->device_removed || (1 == Adapter->downloadDDR);
+}
+
 /**
 @ingroup tx_functions
 Transmit thread
@@ -420,57 +194,26 @@ Transmit thread
 int tx_pkt_handler(PMINI_ADAPTER Adapter  /**< pointer to adapter object*/
                                )
 {
-#ifndef BCM_SHM_INTERFACE
        int status = 0;
-#endif
-
-       UINT calltransmit = 1;
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Entring to wait for signal from the interrupt service thread!Adapter = %p",Adapter);
-
 
-       while(1)
-       {
-               if(Adapter->LinkUpStatus){
+       while(! kthread_should_stop()) {
+               /* FIXME - the timeout looks like workaround for racey usage of TxPktAvail */
+               if(Adapter->LinkUpStatus)
                        wait_event_timeout(Adapter->tx_packet_wait_queue,
-                               ((atomic_read(&Adapter->TxPktAvail) &&
-                               (MINIMUM_PENDING_DESCRIPTORS <
-                               atomic_read(&Adapter->CurrNumFreeTxDesc)) &&
-                               (Adapter->device_removed == FALSE))) ||
-                               (1 == Adapter->downloadDDR) || kthread_should_stop()
-#ifndef BCM_SHM_INTERFACE
-                               || (TRUE == Adapter->bEndPointHalted)
-#endif
-                               , msecs_to_jiffies(10));
-               }
-               else{
-                       wait_event(Adapter->tx_packet_wait_queue,
-                               ((atomic_read(&Adapter->TxPktAvail) &&
-                               (MINIMUM_PENDING_DESCRIPTORS <
-                               atomic_read(&Adapter->CurrNumFreeTxDesc)) &&
-                               (Adapter->device_removed == FALSE))) ||
-                               (1 == Adapter->downloadDDR) || kthread_should_stop()
-#ifndef BCM_SHM_INTERFACE
-                               || (TRUE == Adapter->bEndPointHalted)
-#endif
-                               );
-               }
-
-               if(kthread_should_stop() || Adapter->device_removed)
-               {
-                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Exiting the tx thread..\n");
-                       Adapter->transmit_packet_thread = NULL;
-                       return 0;
-               }
+                                          tx_pending(Adapter), msecs_to_jiffies(10));
+               else
+                       wait_event_interruptible(Adapter->tx_packet_wait_queue,
+                                                tx_pending(Adapter));
 
-#ifndef BCM_SHM_INTERFACE
+               if (Adapter->device_removed)
+                       break;
 
                if(Adapter->downloadDDR == 1)
                {
-                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Downloading DDR Settings\n");
                        Adapter->downloadDDR +=1;
                        status = download_ddr_settings(Adapter);
                        if(status)
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "DDR DOWNLOAD FAILED!\n");
+                               pr_err(PFX "DDR DOWNLOAD FAILED! %d\n", status);
                        continue;
                }
 
@@ -489,7 +232,6 @@ int tx_pkt_handler(PMINI_ADAPTER Adapter  /**< pointer to adapter object*/
                                update_per_sf_desc_cnts(Adapter);
                        }
                }
-#endif
 
                if( atomic_read(&Adapter->CurrNumFreeTxDesc) &&
                        Adapter->LinkStatus == SYNC_UP_REQUEST &&
@@ -507,49 +249,12 @@ int tx_pkt_handler(PMINI_ADAPTER Adapter  /**< pointer to adapter object*/
                                wake_up(&Adapter->process_rx_cntrlpkt);
                }
 
-#ifdef BCM_SHM_INTERFACE
-               spin_lock_bh(&Adapter->txtransmitlock);
-               if(Adapter->txtransmit_running == 0)
-               {
-                       Adapter->txtransmit_running = 1;
-                       calltransmit = 1;
-               }
-               else
-                       calltransmit = 0;
-               spin_unlock_bh(&Adapter->txtransmitlock);
-#endif
-
-               if(calltransmit)
-                       transmit_packets(Adapter);
+               transmit_packets(Adapter);
 
                atomic_set(&Adapter->TxPktAvail, 0);
        }
-       return 0;
-}
-
-#ifdef BCM_SHM_INTERFACE
-extern PMINI_ADAPTER psAdaptertest;
-void  virtual_mail_box_interrupt(void)
-{
-
-#ifndef GDMA_INTERFACE
-       PUINT ptr =  (PUINT)CPE_VIRTUAL_MAILBOX_REG;
-       UINT intval = (UINT)((*ptr & 0xFF00) >> 8);
-       if (intval != 0)
-       {
-               atomic_set(&psAdaptertest->CurrNumFreeTxDesc,   intval);
-               atomic_set (&psAdaptertest->uiMBupdate, TRUE);
 
-               //make it to 0
-               *ptr = *ptr & 0xffff00ff;
-       }
-#endif
-}
-unsigned int total_tx_pkts_pending(void)
-{
-       return atomic_read(&psAdaptertest->TotalPacketCount);
+       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Exiting the tx thread..\n");
+       Adapter->transmit_packet_thread = NULL;
+       return 0;
 }
-
-#endif
-
-
index 4cbe30022248070a4e772920914faefc5d694a46..890778450a86fcefd55d60015064e0ce7068c021 100644 (file)
@@ -2,19 +2,6 @@
 #define CNTRL_SIGNALING_INTERFACE_
 
 
-#ifdef BECEEM_TARGET
-
-#include <mac_common.h>
-#include <msg_Dsa.h>
-#include <msg_Dsc.h>
-#include <msg_Dsd.h>
-#include <sch_definitions.h>
-using namespace Beceem;
-#ifdef ENABLE_CORRIGENDUM2_UPDATE
-extern B_UINT32 g_u32Corr2MacFlags;
-#endif
-
-#else
 
 
 #define DSA_REQ 11
@@ -28,7 +15,6 @@ extern B_UINT32 g_u32Corr2MacFlags;
 #define DSD_ACK 19
 #define MAX_CLASSIFIERS_IN_SF  4
 
-#endif
 
 #define MAX_STRING_LEN 20
 #define MAX_PHS_LENGTHS 255
@@ -57,37 +43,7 @@ extern B_UINT32 g_u32Corr2MacFlags;
 ////////////////////////structure Definitions///////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
 /// \brief class cCPacketClassificationRule
-#ifdef BECEEM_TARGET
-class CCPacketClassificationRuleSI{
-       public:
-               /// \brief Constructor for the class
-       CCPacketClassificationRuleSI():
-               u8ClassifierRulePriority(mClassifierRulePriority),
-               u8IPTypeOfServiceLength(mIPTypeOfService),
-               u8Protocol(mProtocol),
-               u8IPMaskedSourceAddressLength(0),
-               u8IPDestinationAddressLength(0),
-               u8ProtocolSourcePortRangeLength(0),
-               u8ProtocolDestPortRangeLength(0),
-               u8EthernetDestMacAddressLength(0),
-               u8EthernetSourceMACAddressLength(0),
-               u8EthertypeLength(0),
-               u16UserPriority(mUserPriority),
-               u16VLANID(mVLANID),
-               u8AssociatedPHSI(mAssociatedPHSI),
-               u16PacketClassificationRuleIndex(mPacketClassifierRuleIndex),
-               u8VendorSpecificClassifierParamLength(mVendorSpecificClassifierParamLength),
-               u8IPv6FlowLableLength(mIPv6FlowLableLength),
-               u8ClassifierActionRule(mClassifierActionRule)
-
-               {}
-              void Reset()
-              {
-                    CCPacketClassificationRuleSI();
-              }
-#else
 struct _stCPacketClassificationRuleSI{
-#endif
 
        /**  16bit UserPriority Of The Service Flow*/
     B_UINT16                        u16UserPriority;
@@ -145,29 +101,10 @@ struct _stCPacketClassificationRuleSI{
     B_UINT8                                                    u8ClassifierActionRule;
     B_UINT16                                                   u16ValidityBitMap;
 };
-#ifndef BECEEM_TARGET
 typedef struct _stCPacketClassificationRuleSI CCPacketClassificationRuleSI,stCPacketClassificationRuleSI, *pstCPacketClassificationRuleSI;
-#endif
 
 /// \brief class CPhsRuleSI
-#ifdef BECEEM_TARGET
-class CPhsRuleSI{
-       public:
-               /// \brief Constructor for the class
-               CPhsRuleSI():
-                       u8PHSI(mPHSI),
-                       u8PHSFLength(0),
-                       u8PHSMLength(0),
-                       u8PHSS(mPHSS),
-                       u8PHSV(mPHSV),
-                       u8VendorSpecificPHSParamsLength(mVendorSpecificPHSParamLength){}
-                void Reset()
-                {
-                       CPhsRuleSI();
-                }
-#else
 typedef struct _stPhsRuleSI {
-#endif
        /**  8bit PHS Index Of The Service Flow*/
     B_UINT8                         u8PHSI;
        /**  PHSF Length Of The Service Flow*/
@@ -188,31 +125,11 @@ typedef struct _stPhsRuleSI {
     B_UINT8                         u8VendorSpecificPHSParams[VENDOR_PHS_PARAM_LENGTH];
 
        B_UINT8                         u8Padding[2];
-#ifdef BECEEM_TARGET
-};
-#else
 }stPhsRuleSI,*pstPhsRuleSI;
 typedef stPhsRuleSI CPhsRuleSI;
-#endif
 
 /// \brief structure cConvergenceSLTypes
-#ifdef BECEEM_TARGET
-class CConvergenceSLTypes{
-       public:
-               /// \brief Constructor for the class
-               CConvergenceSLTypes():
-               u8ClassfierDSCAction(mClassifierDSCAction),
-               u8PhsDSCAction  (mPhsDSCAction)
-               {}
-              void Reset()
-              {
-                    CConvergenceSLTypes();
-                    cCPacketClassificationRule.Reset();
-                    cPhsRule.Reset();
-              }
-#else
 struct _stConvergenceSLTypes{
-#endif
        /**  8bit Phs Classfier Action Of The Service Flow*/
     B_UINT8                         u8ClassfierDSCAction;
        /**  8bit Phs DSC Action Of The Service Flow*/
@@ -220,111 +137,15 @@ struct _stConvergenceSLTypes{
        /**   16bit Padding */
     B_UINT8                         u8Padding[2];
     /// \brief class cCPacketClassificationRule
-#ifdef BECEEM_TARGET
-    CCPacketClassificationRuleSI      cCPacketClassificationRule;
-#else
     stCPacketClassificationRuleSI     cCPacketClassificationRule;
-#endif
     /// \brief class CPhsRuleSI
-#ifdef BECEEM_TARGET
-    CPhsRuleSI                         cPhsRule;
-#else
      struct _stPhsRuleSI               cPhsRule;
-#endif
 };
-#ifndef BECEEM_TARGET
 typedef struct _stConvergenceSLTypes stConvergenceSLTypes,CConvergenceSLTypes, *pstConvergenceSLTypes;
-#endif
 
 
 /// \brief structure CServiceFlowParamSI
-#ifdef BECEEM_TARGET
-class CServiceFlowParamSI{
-       public:
-               /// \brief Constructor for the class
-               CServiceFlowParamSI():
-                       u32SFID(mSFid),
-                       u16CID(mCid),
-                       u8ServiceClassNameLength(mServiceClassNameLength),
-                       u8MBSService(mMBSService),
-                       u8QosParamSet(mQosParamSetType),
-                       u8TrafficPriority(mTrafficPriority),
-                       u32MaxSustainedTrafficRate(mMaximumSustainedTrafficRate),
-                       u32MaxTrafficBurst(mMaximumTrafficBurst),
-                       u32MinReservedTrafficRate(mMinimumReservedTrafficRate),
-                       u8ServiceFlowSchedulingType(mServiceFlowSchedulingType),
-                       u8RequesttransmissionPolicy(mRequestTransmissionPolicy),
-                       u32ToleratedJitter(mToleratedJitter),
-                       u32MaximumLatency(mMaximumLatency),
-                       u8FixedLengthVSVariableLengthSDUIndicator
-                       (mFixedLengthVSVariableLength),
-                       u8SDUSize(mSDUSize),
-                       u16TargetSAID(mTargetSAID),
-                       u8ARQEnable(mARQEnable),
-                       u16ARQWindowSize(mARQWindowSize),
-                       u16ARQBlockLifeTime(mARQBlockLifeTime),
-                       u16ARQSyncLossTimeOut(mARQSyncLossTimeOut),
-                       u8ARQDeliverInOrder(mARQDeliverInOrder),
-                       u16ARQRxPurgeTimeOut(mARQRXPurgeTimeOut),
-                       //Add ARQ BLOCK SIZE, ARQ TX and RX delay initializations here
-                       //after we move to only CORR2
-                       u8RxARQAckProcessingTime(mRxARQAckProcessingTime),
-                       u8CSSpecification(mCSSpecification),
-                       u8TypeOfDataDeliveryService(mTypeOfDataDeliveryService),
-                       u16SDUInterArrivalTime(mSDUInterArrivalTime),
-                       u16TimeBase(mTimeBase),
-                       u8PagingPreference(mPagingPreference),
-                       u8MBSZoneIdentifierassignment(mMBSZoneIdentifierassignmentLength),
-                       u8TrafficIndicationPreference(mTrafficIndicationPreference),
-                       u8GlobalServicesClassNameLength(mGlobalServicesClassNameLength),
-                       u8SNFeedbackEnabled(mSNFeedbackEnabled),
-                       u8FSNSize(mFSNSize),
-                       u8CIDAllocation4activeBSsLength(mCIDAllocation4activeBSsLength),
-                       u16UnsolicitedGrantInterval(mUnsolicitedGrantInterval),
-                       u16UnsolicitedPollingInterval(mUnsolicitedPollingInterval),
-                       u8PDUSNExtendedSubheader4HarqReordering(mPDUSNExtendedSubheader4HarqReordering),
-                       u8MBSContentsIDLength(mMBSContentsIDLength),
-                       u8HARQServiceFlows(mHARQServiceFlows),
-                       u8AuthTokenLength(mAuthTokenLength),
-                       u8HarqChannelMappingLength(mHarqChannelMappingLength),
-                       u8VendorSpecificQoSParamLength(mVendorSpecificQoSParamLength),
-            bValid(FALSE),
-            u8TotalClassifiers()
-{
-//Remove the bolck after we move to Corr2 only code
-#ifdef ENABLE_CORRIGENDUM2_UPDATE
-       if((g_u32Corr2MacFlags & CORR_2_DSX)  ||  (g_u32Corr2MacFlags & CORR_2_ARQ))
-       {
-       /* IEEE Comment #627 / MTG Comment #426 */
-               u16ARQBlockSize = mARQBlockSize;
-               if(g_u32Corr2MacFlags & CORR_2_ARQ) {
-                       u16ARQRetryTxTimeOut = mARQRetryTimeOutTxDelay;
-                       if(g_u32VENDOR_TYPE == VENDOR_ALCATEL) {
-                               u16ARQRetryRxTimeOut = mARQRetryTimeOutRxDelay_ALU;
-                       } else {
-                               u16ARQRetryRxTimeOut = mARQRetryTimeOutRxDelay;
-                       }
-               }
-               else
-               {
-                       u16ARQRetryTxTimeOut = mARQRetryTimeOutTxDelayCorr1;
-                       u16ARQRetryRxTimeOut = mARQRetryTimeOutRxDelayCorr1;
-               }
-       }
-       else
-#endif
-       {
-               u16ARQBlockSize = mARQBlockSizeCorr1;
-               u16ARQRetryTxTimeOut = mARQRetryTimeOutTxDelayCorr1;
-               u16ARQRetryRxTimeOut = mARQRetryTimeOutRxDelayCorr1;
-       }
-}
-
-       void ComputeMacOverhead(B_UINT8 u8SecOvrhead);
-       B_UINT16        GetMacOverhead() { return       u16MacOverhead; }
-#else
 typedef struct _stServiceFlowParamSI{
-#endif //end of ifdef BECEEM_TARGET
 
      /**  32bitSFID Of The Service Flow*/
     B_UINT32                        u32SFID;
@@ -367,11 +188,6 @@ typedef struct _stServiceFlowParamSI{
 
         /**  16bit ARQ Purge timeout */
     B_UINT16                        u16ARQRxPurgeTimeOut;
-#if 0 //def ENABLE_CORRIGENDUM2_UPDATE
-/* IEEE Comment #627 / MTG Comment #426 */
-    /// \brief Size of an ARQ block, changed from 2 bytes to 1
-    B_UINT8                        u8ARQBlockSize;
-#endif
 //TODO::Remove this once we move to a new CORR2 driver
     /// \brief Size of an ARQ block
     B_UINT16                        u16ARQBlockSize;
@@ -496,35 +312,18 @@ typedef struct _stServiceFlowParamSI{
        B_UINT8                                                 bValid; /**<  Validity flag */
        B_UINT8                         u8Padding;       /**<  Padding byte*/
 
-#ifdef BECEEM_TARGET
-/**
-Structure for Convergence SubLayer Types with a maximum of 4 classifiers
-*/
-       CConvergenceSLTypes             cConvergenceSLTypes[MAX_CLASSIFIERS_IN_SF];
-#else
 /**
 Structure for Convergence SubLayer Types with a maximum of 4 classifiers
 */
        stConvergenceSLTypes            cConvergenceSLTypes[MAX_CLASSIFIERS_IN_SF];
-#endif
 
-#ifdef BECEEM_TARGET
-};
-#else
 } stServiceFlowParamSI, *pstServiceFlowParamSI;
 typedef stServiceFlowParamSI CServiceFlowParamSI;
-#endif
 
 /**
 structure stLocalSFAddRequest
 */
 typedef struct _stLocalSFAddRequest{
-#ifdef BECEEM_TARGET
-          _stLocalSFAddRequest( ) :
-               u8Type(0x00),  eConnectionDir(0x00),
-               u16TID(0x0000), u16CID(0x0000),  u16VCID(0x0000)
-                       {}
-#endif
 
        B_UINT8                         u8Type; /**<  Type*/
        B_UINT8      eConnectionDir;            /**<  Connection direction*/
@@ -535,19 +334,9 @@ typedef struct _stLocalSFAddRequest{
        /// \brief 16bitVCID
        B_UINT16                        u16VCID;        /**<  16bit VCID*/
     /// \brief structure ParameterSet
-#ifdef BECEEM_SIGNALLING_INTERFACE_API
-       CServiceFlowParamSI sfParameterSet;
-#endif
 
-#ifdef BECEEM_TARGET
-    CServiceFlowParamSI              *psfParameterSet;
-#else
        stServiceFlowParamSI    *psfParameterSet;       /**<  structure ParameterSet*/
-#endif
 
-#ifdef USING_VXWORKS
-    USE_DATA_MEMORY_MANAGER();
-#endif
 }stLocalSFAddRequest, *pstLocalSFAddRequest;
 
 
@@ -555,12 +344,6 @@ typedef struct _stLocalSFAddRequest{
 structure stLocalSFAddIndication
 */
 typedef struct _stLocalSFAddIndication{
-#ifdef BECEEM_TARGET
-          _stLocalSFAddIndication( ) :
-               u8Type(0x00),  eConnectionDir(0x00),
-               u16TID(0x0000), u16CID(0x0000),  u16VCID(0x0000)
-                       {}
-#endif
 
        B_UINT8                         u8Type; /**<  Type*/
        B_UINT8      eConnectionDir;    /**<  Connection Direction*/
@@ -571,37 +354,19 @@ typedef struct _stLocalSFAddIndication{
     /// \brief 16bitVCID
     B_UINT16                        u16VCID;    /**<  16bitVCID*/
 
-#ifdef         BECEEM_SIGNALLING_INTERFACE_API
-       CServiceFlowParamSI              sfAuthorizedSet;
-    /// \brief structure AdmittedSet
-    CServiceFlowParamSI              sfAdmittedSet;
-    /// \brief structure ActiveSet
-    CServiceFlowParamSI              sfActiveSet;
-#endif
 
     /// \brief structure AuthorizedSet
-#ifdef BECEEM_TARGET
-    CServiceFlowParamSI              *psfAuthorizedSet;
-    /// \brief structure AdmittedSet
-    CServiceFlowParamSI              *psfAdmittedSet;
-    /// \brief structure ActiveSet
-    CServiceFlowParamSI              *psfActiveSet;
-#else
     /// \brief structure AuthorizedSet
     stServiceFlowParamSI              *psfAuthorizedSet;       /**<  AuthorizedSet of type stServiceFlowParamSI*/
     /// \brief structure AdmittedSet
     stServiceFlowParamSI              *psfAdmittedSet; /**<  AdmittedSet of type stServiceFlowParamSI*/
     /// \brief structure ActiveSet
     stServiceFlowParamSI              *psfActiveSet;   /**<  sfActiveSet of type stServiceFlowParamSI*/
-#endif
        B_UINT8                            u8CC;        /**<  Confirmation Code*/
        B_UINT8                            u8Padd;              /**<  8-bit Padding */
 
     B_UINT16               u16Padd;    /**< 16 bit Padding */
 
-#ifdef USING_VXWORKS
-    USE_DATA_MEMORY_MANAGER();
-#endif
 }stLocalSFAddIndication;
 
 
@@ -619,33 +384,17 @@ typedef struct _stLocalSFAddIndication stLocalSFChangeIndication, *pstLocalSFCha
 structure stLocalSFDeleteRequest
 */
 typedef struct _stLocalSFDeleteRequest{
-#ifdef BECEEM_TARGET
-          _stLocalSFDeleteRequest( ) :
-               u8Type(0x00),  u8Padding(0x00),
-               u16TID(0x0000), u32SFID (0x00000000)
-                       {}
-#endif
        B_UINT8                         u8Type;  /**< Type*/
        B_UINT8                         u8Padding;       /**<  Padding byte*/
        B_UINT16                        u16TID;          /**<  TID*/
     /// \brief 32bitSFID
     B_UINT32                        u32SFID;    /**<  SFID*/
-#ifdef USING_VXWORKS
-    USE_DATA_MEMORY_MANAGER();
-#endif
 }stLocalSFDeleteRequest, *pstLocalSFDeleteRequest;
 
 /**
 structure stLocalSFDeleteIndication
 */
 typedef struct stLocalSFDeleteIndication{
-#ifdef BECEEM_TARGET
-          stLocalSFDeleteIndication( ) :
-               u8Type(0x00),  u8Padding(0x00),
-               u16TID(0x0000), u16CID(0x0000),
-               u16VCID(0x0000),u32SFID (0x00000000)
-                       {}
-#endif
        B_UINT8                         u8Type; /**< Type */
        B_UINT8                         u8Padding;      /**< Padding  */
        B_UINT16                        u16TID;                 /**< TID */
@@ -658,9 +407,6 @@ typedef struct stLocalSFDeleteIndication{
        /// \brief 8bit Confirmation code
        B_UINT8                         u8ConfirmationCode;     /**< Confirmation code */
        B_UINT8                         u8Padding1[3];          /**< 3 byte Padding  */
-#ifdef USING_VXWORKS
-    USE_DATA_MEMORY_MANAGER();
-#endif
 }stLocalSFDeleteIndication;
 
 typedef struct _stIM_SFHostNotify
index 9d4e3aca1b34faf640a4c2b81b5777474b81dfd7..473f11eebf7c22fbffaecdb58d5b87e3dfc61762 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/etherdevice.h>
 #include <net/ip.h>
 #include <linux/wait.h>
-#include <linux/notifier.h>
 #include <linux/proc_fs.h>
 #include <linux/interrupt.h>
 
 #endif
 #include <linux/tcp.h>
 #include <linux/udp.h>
-#ifndef BCM_SHM_INTERFACE
 #include <linux/usb.h>
-#endif
-#ifdef BECEEM_TARGET
-
-#include <mac_common.h>
-#include <msg_Dsa.h>
-#include <msg_Dsc.h>
-#include <msg_Dsd.h>
-#include <sch_definitions.h>
-using namespace Beceem;
-#ifdef ENABLE_CORRIGENDUM2_UPDATE
-extern B_UINT32 g_u32Corr2MacFlags;
-#endif
-#endif
 
 #include "Typedefs.h"
 #include "Version.h"
@@ -71,39 +56,28 @@ extern B_UINT32 g_u32Corr2MacFlags;
 #include "CmHost.h"
 #include "DDRInit.h"
 #include "Debug.h"
-#include "HostMibs.h"
 #include "IPv6ProtocolHdr.h"
-#include "osal_misc.h"
 #include "PHSModule.h"
 #include "Protocol.h"
 #include "Prototypes.h"
 #include "Queue.h"
 #include "vendorspecificextn.h"
 
-#ifndef BCM_SHM_INTERFACE
 
 #include "InterfaceMacros.h"
 #include "InterfaceAdapter.h"
 #include "InterfaceIsr.h"
-#include "Interfacemain.h"
 #include "InterfaceMisc.h"
 #include "InterfaceRx.h"
 #include "InterfaceTx.h"
-#endif
 #include "InterfaceIdleMode.h"
 #include "InterfaceInit.h"
 
-#ifdef BCM_SHM_INTERFACE
-#include <linux/cpe_config.h>
-
-#ifdef GDMA_INTERFACE
-#include "GdmaInterface.h"
-#include "symphony.h"
-#else
-#include "virtual_interface.h"
-
-#endif
-
-#endif
+#define DRV_NAME       "beceem"
+#define DEV_NAME       "tarang"
+#define DRV_DESCRIPTION "Beceem Communications Inc. WiMAX driver"
+#define DRV_COPYRIGHT  "Copyright 2010. Beceem Communications Inc"
+#define DRV_VERSION    VER_FILEVERSION_STR
+#define PFX            DRV_NAME " "
 
 #endif
index e9da513b3c243cd9c3dfcdb59c323d4abbfedac0..c13ea5c9a2aa0823e7e3d0e120ff76fa15a610d6 100644 (file)
  */
 #include "headers.h"
 
-INT  ProcessGetHostMibs(PMINI_ADAPTER Adapter,
-                                                 PVOID ioBuffer,
-                                                 ULONG inputBufferLength)
+INT  ProcessGetHostMibs(PMINI_ADAPTER Adapter, S_MIBS_HOST_STATS_MIBS *pstHostMibs)
 {
-
-       S_MIBS_HOST_STATS_MIBS *pstHostMibs         = NULL;
        S_SERVICEFLOW_ENTRY    *pstServiceFlowEntry = NULL;
        S_PHS_RULE             *pstPhsRule          = NULL;
        S_CLASSIFIER_TABLE     *pstClassifierTable  = NULL;
@@ -30,15 +26,6 @@ INT  ProcessGetHostMibs(PMINI_ADAPTER Adapter,
                return STATUS_FAILURE;
        }
 
-       if(ioBuffer == NULL)
-       {
-               return -EINVAL;
-       }
-       memset(ioBuffer,0,sizeof(S_MIBS_HOST_STATS_MIBS));
-
-       pstHostMibs = (S_MIBS_HOST_STATS_MIBS *)ioBuffer;
-
-
        //Copy the classifier Table
        for(nClassifierIndex=0; nClassifierIndex < MAX_CLASSIFIERS;
                        nClassifierIndex++)
@@ -54,7 +41,7 @@ INT  ProcessGetHostMibs(PMINI_ADAPTER Adapter,
        {
        if(Adapter->PackInfo[nSfIndex].bValid)
        {
-                       OsalMemMove((PVOID)&pstHostMibs->astSFtable[nSfIndex],(PVOID)&Adapter->PackInfo[nSfIndex],sizeof(S_MIBS_SERVICEFLOW_TABLE));
+                       memcpy((PVOID)&pstHostMibs->astSFtable[nSfIndex],(PVOID)&Adapter->PackInfo[nSfIndex],sizeof(S_MIBS_SERVICEFLOW_TABLE));
        }
        else
        {
@@ -83,7 +70,7 @@ INT  ProcessGetHostMibs(PMINI_ADAPTER Adapter,
 
                        pstHostMibs->astPhsRulesTable[nPhsTableIndex].ulSFID = Adapter->PackInfo[nSfIndex].ulSFID;
 
-                       OsalMemMove(&pstHostMibs->astPhsRulesTable[nPhsTableIndex].u8PHSI,
+                       memcpy(&pstHostMibs->astPhsRulesTable[nPhsTableIndex].u8PHSI,
                                                &pstPhsRule->u8PHSI,
                                                sizeof(S_PHS_RULE));
                                nPhsTableIndex++;
@@ -95,12 +82,9 @@ INT  ProcessGetHostMibs(PMINI_ADAPTER Adapter,
        }
 
 
-
        //copy other Host Statistics parameters
-       pstHostMibs->stHostInfo.GoodTransmits =
-                               atomic_read(&Adapter->TxTotalPacketCount);
-       pstHostMibs->stHostInfo.GoodReceives =
-                               atomic_read(&Adapter->GoodRxPktCount);
+       pstHostMibs->stHostInfo.GoodTransmits = Adapter->dev->stats.tx_packets;
+       pstHostMibs->stHostInfo.GoodReceives = Adapter->dev->stats.rx_packets;
        pstHostMibs->stHostInfo.CurrNumFreeDesc =
                        atomic_read(&Adapter->CurrNumFreeTxDesc);
        pstHostMibs->stHostInfo.BEBucketSize = Adapter->BEBucketSize;
@@ -115,13 +99,10 @@ INT  ProcessGetHostMibs(PMINI_ADAPTER Adapter,
 }
 
 
-INT GetDroppedAppCntrlPktMibs(PVOID ioBuffer, PPER_TARANG_DATA pTarang)
+VOID GetDroppedAppCntrlPktMibs(S_MIBS_HOST_STATS_MIBS *pstHostMibs, const PPER_TARANG_DATA pTarang)
 {
-       S_MIBS_HOST_STATS_MIBS *pstHostMibs = (S_MIBS_HOST_STATS_MIBS *)ioBuffer;
-
-       memcpy((PVOID)&(pstHostMibs->stDroppedAppCntrlMsgs),(PVOID)&(pTarang->stDroppedAppCntrlMsgs),sizeof(S_MIBS_DROPPED_APP_CNTRL_MESSAGES));
-
-       return STATUS_SUCCESS ;
+       memcpy(&(pstHostMibs->stDroppedAppCntrlMsgs),
+              &(pTarang->stDroppedAppCntrlMsgs),sizeof(S_MIBS_DROPPED_APP_CNTRL_MESSAGES));
 }
 
 
index 97adaae7dfc0c4fef031a24854c9223ad3bf0610..16e939fa15d64190dfd5835a4268d25baf332c2a 100644 (file)
@@ -108,52 +108,16 @@ static INT LED_Proportional_Blink(PMINI_ADAPTER Adapter, UCHAR GPIO_Num_tx,
        ulong timeout = 0;
 
        /*Read initial value of packets sent/received */
-       Initial_num_of_packts_tx = atomic_read(&Adapter->TxTotalPacketCount);
-       Initial_num_of_packts_rx = atomic_read(&Adapter->GoodRxPktCount);
+       Initial_num_of_packts_tx = Adapter->dev->stats.tx_packets;
+       Initial_num_of_packts_rx = Adapter->dev->stats.rx_packets;
+
        /*Scale the rate of transfer to no of blinks.*/
        num_of_time_tx= ScaleRateofTransfer((ULONG)rate_of_transfer_tx);
        num_of_time_rx= ScaleRateofTransfer((ULONG)rate_of_transfer_rx);
 
        while((Adapter->device_removed == FALSE))
        {
-               #if 0
-               if(0 == num_of_time_tx && 0 == num_of_time_rx)
-               {
-                       timeout = 1000;
-                       Status = wait_event_interruptible_timeout(Adapter->LEDInfo.notify_led_event,
-                               currdriverstate!= Adapter->DriverState || kthread_should_stop(),
-                               msecs_to_jiffies (timeout));
-                       if(kthread_should_stop())
-                       {
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, "Led thread got signal to exit..hence exiting");
-                               Adapter->LEDInfo.led_thread_running= BCM_LED_THREAD_DISABLED;
-                               return EVENT_SIGNALED;
-                       }
-                       if(Status)
-                               return EVENT_SIGNALED;
-
-               }
-               #endif
-
                timeout = 50;
-               #if 0
-               /*Turn on LED if Tx is high bandwidth*/
-               if(num_of_time_tx > MAX_NUM_OF_BLINKS)
-               {
-                       TURN_ON_LED(1<<GPIO_Num_tx, uiTxLedIndex);
-                       num_of_time_tx = 0;
-                       bBlinkBothLED = FALSE;
-                       num_of_time = num_of_time_rx;
-               }
-                       /*Turn on LED if Rx is high bandwidth*/
-               if(num_of_time_rx > MAX_NUM_OF_BLINKS)
-               {
-                       TURN_ON_LED(1<<GPIO_Num_rx, uiRxLedIndex);
-                       num_of_time_rx = 0;
-                       bBlinkBothLED = FALSE;
-                       num_of_time = num_of_time_tx;
-               }
-               #endif
                /*Blink Tx and Rx LED when both Tx and Rx is in normal bandwidth*/
                if(bBlinkBothLED)
                {
@@ -249,9 +213,10 @@ static INT LED_Proportional_Blink(PMINI_ADAPTER Adapter, UCHAR GPIO_Num_tx,
                 * Read the Tx & Rx packets transmission after 1 second and
                 * calculate rate of transfer
                 */
-               Final_num_of_packts_tx = atomic_read(&Adapter->TxTotalPacketCount);
+               Final_num_of_packts_tx = Adapter->dev->stats.tx_packets;
+               Final_num_of_packts_rx = Adapter->dev->stats.rx_packets;
+
                rate_of_transfer_tx = Final_num_of_packts_tx - Initial_num_of_packts_tx;
-               Final_num_of_packts_rx = atomic_read(&Adapter->GoodRxPktCount);
                rate_of_transfer_rx = Final_num_of_packts_rx - Initial_num_of_packts_rx;
 
                /*Read initial value of packets sent/received */
@@ -293,7 +258,7 @@ static INT ValidateDSDParamsChecksum(
 
        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread:ValidateDSDParamsChecksum: 0x%lx 0x%X",ulParamOffset, usParamLen);
 
-       puBuffer = OsalMemAlloc(usParamLen,"!MEM");
+       puBuffer = kmalloc(usParamLen, GFP_KERNEL);
        if(!puBuffer)
        {
                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: ValidateDSDParamsChecksum Allocation failed");
@@ -341,10 +306,7 @@ static INT ValidateDSDParamsChecksum(
        }
 
 exit:
-       if(puBuffer)
-       {
-               OsalMemFree(puBuffer, usParamLen);
-       }
+       kfree(puBuffer);
        return Status;
 }
 
@@ -497,12 +459,10 @@ static int ReadConfigFileStructure(PMINI_ADAPTER Adapter, BOOLEAN *bEnableThread
 {
        int Status = STATUS_SUCCESS;
        UCHAR GPIO_Array[NUM_OF_LEDS+1]; /*Array to store GPIO numbers from EEPROM*/
-#ifndef BCM_SHM_INTERFACE
        UINT uiIndex = 0;
        UINT uiNum_of_LED_Type = 0;
        PUCHAR puCFGData        = NULL;
        UCHAR bData = 0;
-#endif
        memset(GPIO_Array, DISABLE_GPIO_NUM, NUM_OF_LEDS+1);
 
        if(!Adapter->pstargetparams || IS_ERR(Adapter->pstargetparams))
@@ -524,10 +484,6 @@ static int ReadConfigFileStructure(PMINI_ADAPTER Adapter, BOOLEAN *bEnableThread
                *bEnableThread = FALSE;
                return Status;
        }
-#ifdef BCM_SHM_INTERFACE
-       *bEnableThread = FALSE;
-       return Status ;
-#else
   /*
      * CONFIG file read successfully. Deallocate the memory of
      * uiFileNameBufferSize
@@ -578,23 +534,7 @@ static int ReadConfigFileStructure(PMINI_ADAPTER Adapter, BOOLEAN *bEnableThread
        }
        if(uiNum_of_LED_Type >= NUM_OF_LEDS)
                *bEnableThread = FALSE;
-#endif
 
-#if 0
-       for(uiIndex=0; uiIndex<NUM_OF_LEDS; uiIndex++)
-       {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LEDState[%d].LED_Type = %x\n", uiIndex,
-                       Adapter->LEDInfo.LEDState[uiIndex].LED_Type);
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LEDState[%d].LED_On_State = %x\n", uiIndex,
-                       Adapter->LEDInfo.LEDState[uiIndex].LED_On_State);
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LEDState[%d].LED_Blink_State = %x\n", uiIndex,
-                       Adapter->LEDInfo.LEDState[uiIndex].LED_Blink_State);
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LEDState[%d].GPIO_Num = %x\n", uiIndex,
-                       Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num);
-       }
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: Polarity = %d\n",
-                       Adapter->LEDInfo.BitPolarty);
-#endif
        return Status;
 }
 //--------------------------------------------------------------------------
@@ -721,20 +661,6 @@ static VOID LEDControlThread(PMINI_ADAPTER Adapter)
                        TURN_OFF_LED(1<<GPIO_num, uiLedIndex);
                        return ;//STATUS_FAILURE;
                }
-       #if 0
-               if(Adapter->device_removed)
-               {
-                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"Device removed hence exiting from Led Thread..");
-                       return ; //-ENODEV;
-               }
-       #endif
-               #if 0
-               if((GPIO_num != DISABLE_GPIO_NUM) &&
-                       ((currdriverstate != FW_DOWNLOAD) &&
-                       (currdriverstate != NORMAL_OPERATION) &&
-                       (currdriverstate != IDLEMODE_EXIT)))
-                       TURN_OFF_LED(1<<GPIO_num, uiLedIndex);
-               #endif
 
                if(GPIO_num != DISABLE_GPIO_NUM)
                {
@@ -752,10 +678,6 @@ static VOID LEDControlThread(PMINI_ADAPTER Adapter)
                        case DRIVER_INIT:
                        {
                                currdriverstate = DRIVER_INIT;//Adapter->DriverState;
-       #if 0
-                               LedGpioInit(Adapter);
-                               Adapter->LEDInfo.bLedInitDone = TRUE;
-       #endif
                                BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum, &uiLedIndex, &dummyIndex, currdriverstate);
 
                                if(GPIO_num  != DISABLE_GPIO_NUM)
@@ -768,13 +690,6 @@ static VOID LEDControlThread(PMINI_ADAPTER Adapter)
                        {
                                //BCM_DEBUG_PRINT (Adapter,DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL,"LED Thread: FW_DN_DONE called\n");
                                currdriverstate = FW_DOWNLOAD;
-                       #if 0
-                               if(Adapter->LEDInfo.bLedInitDone == FALSE)
-                               {
-                                       LedGpioInit(Adapter);
-                                       Adapter->LEDInfo.bLedInitDone = TRUE;
-                               }
-                       #endif
                                BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum,  &uiLedIndex, &dummyIndex, currdriverstate);
 
                                if(GPIO_num != DISABLE_GPIO_NUM)
@@ -796,12 +711,6 @@ static VOID LEDControlThread(PMINI_ADAPTER Adapter)
                        break;
 
                        case SHUTDOWN_EXIT:
-                       #if 0
-                       if(Adapter->ulPowerSaveMode == DEVICE_POWERSAVE_MODE_AS_PMU_SHUTDOWN)
-                       {
-                               LedGpioInit(Adapter);
-                       }
-                       #endif
                        //no break, continue to NO_NETWORK_ENTRY state as well.
 
                        case NO_NETWORK_ENTRY:
@@ -875,34 +784,6 @@ static VOID LEDControlThread(PMINI_ADAPTER Adapter)
                        break;
                        case IDLEMODE_EXIT:
                        {
-#if 0
-                               UCHAR GPIO_num_tx = DISABLE_GPIO_NUM;
-                               UCHAR GPIO_num_rx = DISABLE_GPIO_NUM;
-                               UCHAR uiTxLedIndex = 0;
-                               UCHAR uiRxLedIndex = 0;
-
-                               currdriverstate  = IDLEMODE_EXIT;
-                               if(DEVICE_POWERSAVE_MODE_AS_PMU_SHUTDOWN == Adapter->ulPowerSaveMode)
-                               {
-                                       LedGpioInit(Adapter);
-                               }
-                               BcmGetGPIOPinInfo(Adapter, &GPIO_num_tx, &GPIO_num_rx, &uiTxLedIndex,&uiRxLedIndex,currdriverstate);
-
-                               Adapter->LEDInfo.bIdle_led_off =  FALSE;
-
-                               if((GPIO_num_tx == DISABLE_GPIO_NUM) && (GPIO_num_rx == DISABLE_GPIO_NUM))
-                               {
-                                       GPIO_num = DISABLE_GPIO_NUM ;
-                               }
-                               else
-                               {
-                                       timeout = 50;
-                                       if(Adapter->LEDInfo.bIdleMode_tx_from_host)
-                                               LED_Blink(Adapter, 1<<GPIO_num_tx, uiTxLedIndex, timeout, -1,currdriverstate);
-                                       else
-                                               LED_Blink(Adapter, 1<<GPIO_num_rx, uiRxLedIndex, timeout, -1,currdriverstate);
-                               }
-#endif
                        }
                        break;
                        case DRIVER_HALT:
index 41c9ab8a2385585a6c412c6ebb460e913554c0fe..c7292373a65f8fb4c873f4d1a7b05005834b29bd 100644 (file)
@@ -1,6 +1,56 @@
 #include "headers.h"
 
 #define DWORD unsigned int
+
+static INT BcmDoChipSelect(PMINI_ADAPTER Adapter, UINT offset);
+static INT BcmGetActiveDSD(PMINI_ADAPTER Adapter);
+static INT BcmGetActiveISO(PMINI_ADAPTER Adapter);
+static UINT BcmGetEEPROMSize(PMINI_ADAPTER Adapter);
+static INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter);
+static UINT BcmGetFlashSectorSize(PMINI_ADAPTER Adapter, UINT FlashSectorSizeSig, UINT FlashSectorSize);
+
+static VOID BcmValidateNvmType(PMINI_ADAPTER Adapter);
+static INT BcmGetNvmSize(PMINI_ADAPTER Adapter);
+static UINT BcmGetFlashSize(PMINI_ADAPTER Adapter);
+static NVM_TYPE BcmGetNvmType(PMINI_ADAPTER Adapter);
+
+static INT BcmGetSectionValEndOffset(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal);
+
+static B_UINT8 IsOffsetWritable(PMINI_ADAPTER Adapter, UINT uiOffset);
+static INT IsSectionWritable(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL Section);
+static INT IsSectionExistInVendorInfo(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section);
+
+static INT ReadDSDPriority(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL dsd);
+static INT ReadDSDSignature(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL dsd);
+static INT ReadISOPriority(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL iso);
+static INT ReadISOSignature(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL iso);
+
+static INT CorruptDSDSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal);
+static INT CorruptISOSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal);
+static INT SaveHeaderIfPresent(PMINI_ADAPTER Adapter, PUCHAR pBuff, UINT uiSectAlignAddr);
+static INT WriteToFlashWithoutSectorErase(PMINI_ADAPTER Adapter, PUINT pBuff,
+                                         FLASH2X_SECTION_VAL eFlash2xSectionVal,
+                                         UINT uiOffset, UINT uiNumBytes);
+static FLASH2X_SECTION_VAL getHighestPriDSD(PMINI_ADAPTER Adapter);
+static FLASH2X_SECTION_VAL getHighestPriISO(PMINI_ADAPTER Adapter);
+
+static INT BeceemFlashBulkRead(
+       PMINI_ADAPTER Adapter,
+       PUINT pBuffer,
+       UINT uiOffset,
+       UINT uiNumBytes);
+
+static INT BeceemFlashBulkWrite(
+       PMINI_ADAPTER Adapter,
+       PUINT pBuffer,
+       UINT uiOffset,
+       UINT uiNumBytes,
+       BOOLEAN bVerify);
+
+static INT GetFlashBaseAddr(PMINI_ADAPTER Adapter);
+
+static INT ReadBeceemEEPROMBulk(PMINI_ADAPTER Adapter,UINT dwAddress, UINT *pdwData, UINT dwNumData);
+
 // Procedure:  ReadEEPROMStatusRegister
 //
 // Description: Reads the standard EEPROM Status Register.
@@ -228,213 +278,27 @@ INT ReadBeceemEEPROM( PMINI_ADAPTER Adapter,
                ReadBeceemEEPROMBulk(Adapter, uiTempOffset + MAX_RW_SIZE, (PUINT)&uiData[4], 4);
        }
 
-       OsalMemMove( (PUCHAR) pBuffer, ( ((PUCHAR)&uiData[0]) + uiByteOffset ), 4);
+       memcpy( (PUCHAR) pBuffer, ( ((PUCHAR)&uiData[0]) + uiByteOffset ), 4);
 
        return STATUS_SUCCESS;
 } /* ReadBeceemEEPROM() */
 
 
-#if 0
-//-----------------------------------------------------------------------------
-// Procedure:  IsEEPROMWriteDone
-//
-// Description: Reads the SPI status to see the status of previous write.
-//
-// Arguments:
-//             Adapter    - ptr to Adapter object instance
-//
-// Returns:
-//             BOOLEAN - TRUE  - write went through
-//              - FALSE - Write Failed.
-//-----------------------------------------------------------------------------
-
-BOOLEAN IsEEPROMWriteDone(PMINI_ADAPTER Adapter)
-{
-       UINT uiRetries = 16;
-       //UINT uiStatus  = 0;
-       UINT value;
-
-       //sleep for 1.2ms ..worst case EEPROM write can take up to 1.2ms.
-       mdelay(2);
-
-       value = 0;
-       rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value));
-
-       while(((value >> 14) & 1) == 1)
-       {
-               // EEPROM_SPI_Q_STATUS1_REG will be cleared only if write back to that.
-               value = (0x1 << 14);
-               wrmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG,&value, sizeof(value));
-               udelay(1000);
-               uiRetries--;
-               if(uiRetries == 0)
-               {
-                       return FALSE;
-               }
-               value = 0;
-               rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value));
-       }
-       return TRUE;
-
-
-}
-
-
-//-----------------------------------------------------------------------------
-// Procedure:  ReadBeceemEEPROMBulk
-//
-// Description: This routine reads 16Byte data from EEPROM
-//
-// Arguments:
-//             Adapter     - ptr to Adapter object instance
-//          dwAddress - EEPROM Offset to read the data from.
-//          pdwData    - Pointer to double word where data needs to be stored in.
-//
-// Returns:
-//             OSAL_STATUS_CODE:
-//-----------------------------------------------------------------------------
-
-INT ReadBeceemEEPROMBulk(PMINI_ADAPTER Adapter,DWORD dwAddress, DWORD *pdwData)
-{
-       DWORD dwRetries = 16;
-       DWORD dwIndex = 0;
-       UINT value, tmpVal;
-
-
-       value = 0;
-       rdmalt (Adapter, 0x0f003008, &value, sizeof(value));
-
-       //read 0x0f003020 untill  bit 1 of 0x0f003008 is set.
-       while(((value >> 1) & 1) == 0)
-       {
-
-               rdmalt (Adapter, 0x0f003020, &tmpVal, sizeof(tmpVal));
-               dwRetries--;
-               if(dwRetries == 0)
-               {
-                       return -1;
-               }
-               value = 0;
-               rdmalt (Adapter, 0x0f003008, &value, sizeof(value));
-       }
-
-       value = dwAddress | 0xfb000000;
-       wrmalt (Adapter, 0x0f003018, &value, sizeof(value));
-
-       udelay(1000);
-       value = 0;
-       for(dwIndex = 0;dwIndex < 4 ; dwIndex++)
-       {
-               value = 0;
-               rdmalt (Adapter, 0x0f003020, &value, sizeof(value));
-               pdwData[dwIndex] = value;
-
-               value = 0;
-               rdmalt (Adapter, 0x0f003020, &value, sizeof(value));
-               pdwData[dwIndex] |= (value << 8);
-
-               value = 0;
-               rdmalt (Adapter, 0x0f003020, &value, sizeof(value));
-               pdwData[dwIndex] |= (value << 16);
-
-               value = 0;
-               rdmalt (Adapter, 0x0f003020, &value, sizeof(value));
-               pdwData[dwIndex] |= (value << 24);
-
-       }
-       return 0;
-}
-
-//-----------------------------------------------------------------------------
-// Procedure:  ReadBeceemEEPROM
-//
-// Description: This routine reads 4Byte data from EEPROM
-//
-// Arguments:
-//             Adapter     - ptr to Adapter object instance
-//          dwAddress - EEPROM Offset to read the data from.
-//          pdwData    - Pointer to double word where data needs to be stored in.
-//
-// Returns:
-//             OSAL_STATUS_CODE:
-//-----------------------------------------------------------------------------
-
-INT ReadBeceemEEPROM(PMINI_ADAPTER Adapter,DWORD dwAddress, DWORD *pdwData)
-{
-
-       DWORD dwReadValue = 0;
-       DWORD dwRetries = 16, dwCompleteWord = 0;
-       UINT    value, tmpVal;
-
-       rdmalt(Adapter, 0x0f003008, &value, sizeof(value));
-       while (((value >> 1) & 1) == 0) {
-               rdmalt(Adapter, 0x0f003020, &tmpVal, sizeof(tmpVal));
-
-               if (dwRetries == 0) {
-                       return -1;
-               }
-               rdmalt(Adapter, 0x0f003008, &value, sizeof(value));
-       }
-
-
-       //wrm (0x0f003018, 0xNbXXXXXX)      // N is the number of bytes u want to read  (0 means 1, f means 16,   b is the opcode for page read)
-       //     Follow it up by N executions of  rdm(0x0f003020) to read the rxed bytes from rx queue.
-       dwAddress |= 0x3b000000;
-       wrmalt(Adapter, 0x0f003018,&dwAddress,4);
-       mdelay(10);
-       rdmalt(Adapter, 0x0f003020,&dwReadValue,4);
-       dwCompleteWord=dwReadValue;
-       rdmalt(Adapter, 0x0f003020,&dwReadValue,4);
-       dwCompleteWord|=(dwReadValue<<8);
-       rdmalt(Adapter, 0x0f003020,&dwReadValue,4);
-       dwCompleteWord|=(dwReadValue<<16);
-       rdmalt(Adapter, 0x0f003020,&dwReadValue,4);
-       dwCompleteWord|=(dwReadValue<<24);
-
-       *pdwData = dwCompleteWord;
-
-       return 0;
-}
-#endif
 
 INT ReadMacAddressFromNVM(PMINI_ADAPTER Adapter)
 {
-       INT Status=0, i;
-       unsigned char puMacAddr[6] = {0};
-       INT AllZeroMac = 0;
-       INT AllFFMac = 0;
+       INT Status;
+       unsigned char puMacAddr[6];
 
        Status = BeceemNVMRead(Adapter,
                        (PUINT)&puMacAddr[0],
                        INIT_PARAMS_1_MACADDRESS_ADDRESS,
                        MAC_ADDRESS_SIZE);
 
-       if(Status != STATUS_SUCCESS)
-       {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Error in Reading the mac Addres with status :%d", Status);
-               return Status;
-       }
-
-       memcpy(Adapter->dev->dev_addr, puMacAddr, MAC_ADDRESS_SIZE);
-       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Modem MAC Addr :");
-    BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_PRINTK, 0, DBG_LVL_ALL,&Adapter->dev->dev_addr[0],MAC_ADDRESS_SIZE);
-       for(i=0;i<MAC_ADDRESS_SIZE;i++)
-       {
-
-               if(Adapter->dev->dev_addr[i] == 0x00)
-                       AllZeroMac++;
-               if(Adapter->dev->dev_addr[i] == 0xFF)
-                       AllFFMac++;
-
-       }
-       //BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "\n");
-       if(AllZeroMac == MAC_ADDRESS_SIZE)
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Warning :: MAC Address has all 00's");
-       if(AllFFMac == MAC_ADDRESS_SIZE)
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Warning :: MAC Address has all FF's");
+       if(Status == STATUS_SUCCESS)
+               memcpy(Adapter->dev->dev_addr, puMacAddr, MAC_ADDRESS_SIZE);
 
        return Status;
-
 }
 
 //-----------------------------------------------------------------------------
@@ -476,7 +340,7 @@ INT BeceemEEPROMBulkRead(
                ReadBeceemEEPROMBulk(Adapter,uiTempOffset,(PUINT)&uiData[0],4);
                if(uiBytesRemaining >= (MAX_RW_SIZE - uiExtraBytes))
                {
-                       OsalMemMove(pBuffer,(((PUCHAR)&uiData[0])+uiExtraBytes),MAX_RW_SIZE - uiExtraBytes);
+                       memcpy(pBuffer,(((PUCHAR)&uiData[0])+uiExtraBytes),MAX_RW_SIZE - uiExtraBytes);
 
                        uiBytesRemaining -= (MAX_RW_SIZE - uiExtraBytes);
                        uiIndex += (MAX_RW_SIZE - uiExtraBytes);
@@ -484,7 +348,7 @@ INT BeceemEEPROMBulkRead(
                }
                else
                {
-                       OsalMemMove(pBuffer,(((PUCHAR)&uiData[0])+uiExtraBytes),uiBytesRemaining);
+                       memcpy(pBuffer,(((PUCHAR)&uiData[0])+uiExtraBytes),uiBytesRemaining);
                        uiIndex += uiBytesRemaining;
                        uiOffset += uiBytesRemaining;
                        uiBytesRemaining = 0;
@@ -508,7 +372,7 @@ INT BeceemEEPROMBulkRead(
                         * We read 4 Dwords of data */
                        if(0 == ReadBeceemEEPROMBulk(Adapter,uiOffset,&uiData[0],4))
                        {
-                               OsalMemMove(pcBuff+uiIndex,&uiData[0],MAX_RW_SIZE);
+                               memcpy(pcBuff+uiIndex,&uiData[0],MAX_RW_SIZE);
                                uiOffset += MAX_RW_SIZE;
                                uiBytesRemaining -= MAX_RW_SIZE;
                                uiIndex += MAX_RW_SIZE;
@@ -523,7 +387,7 @@ INT BeceemEEPROMBulkRead(
                {
                        if(0 == ReadBeceemEEPROM(Adapter,uiOffset,&uiData[0]))
                        {
-                               OsalMemMove(pcBuff+uiIndex,&uiData[0],4);
+                               memcpy(pcBuff+uiIndex,&uiData[0],4);
                                uiOffset += 4;
                                uiBytesRemaining -= 4;
                                uiIndex +=4;
@@ -540,7 +404,7 @@ INT BeceemEEPROMBulkRead(
                        pCharBuff += uiIndex;
                        if(0 == ReadBeceemEEPROM(Adapter,uiOffset,&uiData[0]))
                        {
-                               OsalMemMove(pCharBuff,&uiData[0],uiBytesRemaining);//copy only bytes requested.
+                               memcpy(pCharBuff,&uiData[0],uiBytesRemaining);//copy only bytes requested.
                                uiBytesRemaining = 0;
                        }
                        else
@@ -571,7 +435,7 @@ INT BeceemEEPROMBulkRead(
 //             <FAILURE>                       - if failed.
 //-----------------------------------------------------------------------------
 
-INT BeceemFlashBulkRead(
+static INT BeceemFlashBulkRead(
        PMINI_ADAPTER Adapter,
        PUINT pBuffer,
        UINT uiOffset,
@@ -653,16 +517,8 @@ INT BeceemFlashBulkRead(
 //
 //-----------------------------------------------------------------------------
 
-UINT BcmGetFlashSize(PMINI_ADAPTER Adapter)
+static UINT BcmGetFlashSize(PMINI_ADAPTER Adapter)
 {
-#if 0
-       if(Adapter->bDDRInitDone)
-       {
-               return rdm(Adapter,FLASH_CONTIGIOUS_START_ADDR_AFTER_INIT|FLASH_SIZE_ADDR);
-       }
-
-       return rdm(Adapter,FLASH_CONTIGIOUS_START_ADDR_BEFORE_INIT|FLASH_SIZE_ADDR);
-#endif
        if(IsFlash2x(Adapter))
                return  (Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + sizeof(DSD_HEADER));
        else
@@ -684,7 +540,7 @@ UINT BcmGetFlashSize(PMINI_ADAPTER Adapter)
 //
 //-----------------------------------------------------------------------------
 
-UINT BcmGetEEPROMSize(PMINI_ADAPTER Adapter)
+static UINT BcmGetEEPROMSize(PMINI_ADAPTER Adapter)
 {
        UINT uiData = 0;
        UINT uiIndex = 0;
@@ -733,60 +589,6 @@ UINT BcmGetEEPROMSize(PMINI_ADAPTER Adapter)
        return 0;
 }
 
-#if 0
-/***********************************************************************************/
-//
-//  WriteBeceemEEPROM: Writes 4 byte data to EEPROM offset.
-//
-//                     uiEEPROMOffset - Offset to be written to.
-//                     uiData         - Data to be written.
-//
-/***********************************************************************************/
-
-INT WriteBeceemEEPROM(PMINI_ADAPTER Adapter,UINT uiEEPROMOffset, UINT uiData)
-{
-       INT Status = 0;
-       ULONG ulRdBk = 0;
-       ULONG ulRetryCount = 3;
-       UINT value;
-
-       if(uiEEPROMOffset > EEPROM_END)
-       {
-
-               return -1;
-       }
-
-       uiData = htonl(uiData);
-       while(ulRetryCount--)
-       {
-               value = 0x06000000;
-               wrmalt(Adapter, 0x0F003018,&value, sizeof(value));//flush the EEPROM FIFO.
-               wrmalt(Adapter, 0x0F00301C,&uiData, sizeof(uiData));
-               value = 0x3A000000 | uiEEPROMOffset;
-               wrmalt(Adapter, 0x0F003018,&value, sizeof(value));
-               __udelay(100000);
-               //read back and verify.
-               Status = ReadBeceemEEPROM(Adapter,uiEEPROMOffset,(UINT *)&ulRdBk);
-               if(Status == 0)
-               {
-                       if(ulRdBk == uiData)
-                       {
-                               return Status;
-                       }
-                       else
-                       {
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "WriteBeceemEEPROM: Readback does not match\n");
-                       }
-               }
-               else
-               {
-                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "WriteBeceemEEPROM: Readback failed\n");
-               }
-       }
-
-       return 0;
-}
-#endif
 
 //-----------------------------------------------------------------------------
 // Procedure:  FlashSectorErase
@@ -973,7 +775,7 @@ static INT flashWrite(
 // need not write 0xFFFFFFFF because write requires an erase and erase will
 // make whole sector 0xFFFFFFFF.
 //
-       if (!OsalMemCompare(pData, uiErasePattern, MAX_RW_SIZE))
+       if (!memcmp(pData, uiErasePattern, MAX_RW_SIZE))
        {
                return 0;
        }
@@ -1138,7 +940,7 @@ static INT flashWriteStatus(
 // need not write 0xFFFFFFFF because write requires an erase and erase will
 // make whole sector 0xFFFFFFFF.
 //
-       if (!OsalMemCompare(pData,uiErasePattern,MAX_RW_SIZE))
+       if (!memcmp(pData,uiErasePattern,MAX_RW_SIZE))
        {
                return 0;
        }
@@ -1332,7 +1134,7 @@ static ULONG BcmFlashUnProtectBlock(PMINI_ADAPTER Adapter,UINT uiOffset, UINT ui
 //
 //-----------------------------------------------------------------------------
 
-INT BeceemFlashBulkWrite(
+static INT BeceemFlashBulkWrite(
        PMINI_ADAPTER Adapter,
        PUINT pBuffer,
        UINT uiOffset,
@@ -1353,15 +1155,6 @@ INT BeceemFlashBulkWrite(
        UINT uiTemp                             = 0;
        UINT index                                      = 0;
        UINT uiPartOffset                       = 0;
-       #if 0
-       struct timeval tv1 = {0};
-       struct timeval tv2 = {0};
-
-       struct timeval tr = {0};
-       struct timeval te = {0};
-       struct timeval tw = {0};
-       struct timeval twv = {0};
-       #endif
 
 #if defined(BCM_SHM_INTERFACE) && !defined(FLASH_DIRECT_ACCESS)
   Status = bcmflash_raw_write((uiOffset/FLASH_PART_SIZE),(uiOffset % FLASH_PART_SIZE),( unsigned char *)pBuffer,uiNumBytes);
@@ -1377,12 +1170,9 @@ INT BeceemFlashBulkWrite(
        uiCurrSectOffsetAddr    = uiOffset & (Adapter->uiSectorSize - 1);
        uiSectBoundary                  = uiSectAlignAddr + Adapter->uiSectorSize;
 
-       //pTempBuff = OsalMemAlloc(MAX_SECTOR_SIZE,'!MVN');
-       pTempBuff = OsalMemAlloc(Adapter->uiSectorSize ,"!MVN");
+       pTempBuff = kmalloc(Adapter->uiSectorSize, GFP_KERNEL);
        if(NULL == pTempBuff)
-       {
                goto BeceemFlashBulkWrite_EXIT;
-       }
 //
 // check if the data to be written is overlapped accross sectors
 //
@@ -1399,7 +1189,6 @@ INT BeceemFlashBulkWrite(
                        uiNumSectTobeRead++;
                }
        }
-       #if 1
        //Check whether Requested sector is writable or not in case of flash2x write. But if  write call is
        // for DSD calibration, allow it without checking of sector permission
 
@@ -1420,7 +1209,6 @@ INT BeceemFlashBulkWrite(
                         index = index + 1 ;
                }
        }
-       #endif
        Adapter->SelectedChip = RESET_CHIP_SELECT;
        while(uiNumSectTobeRead)
        {
@@ -1448,13 +1236,13 @@ INT BeceemFlashBulkWrite(
                if(uiNumSectTobeRead > 1)
                {
 
-                       OsalMemMove(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr));
+                       memcpy(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr));
                        pcBuffer += ((uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr)));
                        uiNumBytes -= (uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr));
                }
                else
                {
-                               OsalMemMove(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiNumBytes);
+                               memcpy(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiNumBytes);
                }
 
                if(IsFlash2x(Adapter))
@@ -1503,7 +1291,7 @@ INT BeceemFlashBulkWrite(
                                }
                                else
                                {
-                                       if(OsalMemCompare(ucReadBk,&pTempBuff[uiIndex],MAX_RW_SIZE))
+                                       if(memcmp(ucReadBk,&pTempBuff[uiIndex],MAX_RW_SIZE))
                                        {
                                                if(STATUS_SUCCESS != (*Adapter->fpFlashWriteWithStatusCheck)(Adapter,uiPartOffset+uiIndex,&pTempBuff[uiIndex]))
                                                {
@@ -1541,10 +1329,8 @@ BeceemFlashBulkWrite_EXIT:
        {
                BcmRestoreBlockProtectStatus(Adapter,ulStatus);
        }
-       if(pTempBuff)
-       {
-               OsalMemFree(pTempBuff,Adapter->uiSectorSize);
-       }
+       
+       kfree(pTempBuff);
 
        Adapter->SelectedChip = RESET_CHIP_SELECT;
        return Status;
@@ -1599,14 +1385,10 @@ static INT BeceemFlashBulkWriteStatus(
        uiCurrSectOffsetAddr    = uiOffset & (Adapter->uiSectorSize - 1);
        uiSectBoundary                  = uiSectAlignAddr + Adapter->uiSectorSize;
 
-
-
-//     pTempBuff = OsalMemAlloc(MAX_SECTOR_SIZE,'!MVN');
-       pTempBuff = OsalMemAlloc(Adapter->uiSectorSize,"!MVN");
+       pTempBuff = kmalloc(Adapter->uiSectorSize, GFP_KERNEL);
        if(NULL == pTempBuff)
-       {
                goto BeceemFlashBulkWriteStatus_EXIT;
-       }
+
 //
 // check if the data to be written is overlapped accross sectors
 //
@@ -1662,13 +1444,13 @@ static INT BeceemFlashBulkWriteStatus(
                if(uiNumSectTobeRead > 1)
                {
 
-                       OsalMemMove(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr));
+                       memcpy(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr));
                        pcBuffer += ((uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr)));
                        uiNumBytes -= (uiSectBoundary-(uiSectAlignAddr+uiCurrSectOffsetAddr));
                }
                else
                {
-                       OsalMemMove(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiNumBytes);
+                       memcpy(&pTempBuff[uiCurrSectOffsetAddr],pcBuffer,uiNumBytes);
                }
 
                if(IsFlash2x(Adapter))
@@ -1698,25 +1480,10 @@ static INT BeceemFlashBulkWriteStatus(
                {
                        for(uiIndex = 0;uiIndex < Adapter->uiSectorSize;uiIndex += MAX_RW_SIZE)
                        {
-#if 0
-                               if(0 == BeceemFlashBulkRead(Adapter,uiReadBk,uiOffsetFromSectStart+uiIndex + Adapter->ulFlashCalStart ,MAX_RW_SIZE))
-                               {
-                                       for(uiReadIndex = 0;uiReadIndex < 4; uiReadIndex++)
-                                       {
-                                               if(*((PUINT)&pTempBuff[uiIndex+uiReadIndex*4]) != uiReadBk[uiReadIndex])
-                                               {
-                                                       Status = -1;
-                                                       goto BeceemFlashBulkWriteStatus_EXIT;
-
-                                               }
-                                       }
-
-                               }
-#endif
 
                                if(STATUS_SUCCESS == BeceemFlashBulkRead(Adapter,(PUINT)ucReadBk,uiOffsetFromSectStart+uiIndex,MAX_RW_SIZE))
                                {
-                                       if(OsalMemCompare(ucReadBk,&pTempBuff[uiIndex],MAX_RW_SIZE))
+                                       if(memcmp(ucReadBk,&pTempBuff[uiIndex],MAX_RW_SIZE))
                                        {
                                                Status = STATUS_FAILURE;
                                                goto BeceemFlashBulkWriteStatus_EXIT;
@@ -1747,10 +1514,8 @@ BeceemFlashBulkWriteStatus_EXIT:
        {
                BcmRestoreBlockProtectStatus(Adapter,ulStatus);
        }
-       if(pTempBuff)
-       {
-               OsalMemFree(pTempBuff,Adapter->uiSectorSize);
-       }
+
+       kfree(pTempBuff);
        Adapter->SelectedChip = RESET_CHIP_SELECT;
        return Status;
 
@@ -1771,7 +1536,7 @@ BeceemFlashBulkWriteStatus_EXIT:
 
 INT PropagateCalParamsFromEEPROMToMemory(PMINI_ADAPTER Adapter)
 {
-       PCHAR pBuff = OsalMemAlloc(BUFFER_4K,"3MVN");
+       PCHAR pBuff = kmalloc(BUFFER_4K, GFP_KERNEL);
        UINT uiEepromSize = 0;
        UINT uiIndex = 0;
        UINT uiBytesToCopy = 0;
@@ -1787,14 +1552,14 @@ INT PropagateCalParamsFromEEPROMToMemory(PMINI_ADAPTER Adapter)
        if(0 != BeceemEEPROMBulkRead(Adapter,&uiEepromSize,EEPROM_SIZE_OFFSET,4))
        {
 
-               OsalMemFree(pBuff,BUFFER_4K);
+               kfree(pBuff);
                return -1;
        }
 
        uiEepromSize >>= 16;
        if(uiEepromSize > 1024*1024)
        {
-               OsalMemFree(pBuff,BUFFER_4K);
+               kfree(pBuff);
                return -1;
        }
 
@@ -1820,7 +1585,7 @@ INT PropagateCalParamsFromEEPROMToMemory(PMINI_ADAPTER Adapter)
        wrmalt(Adapter, EEPROM_CAL_DATA_INTERNAL_LOC-4,&value, sizeof(value));
        value = 0xbeadbead;
        wrmalt(Adapter, EEPROM_CAL_DATA_INTERNAL_LOC-8,&value, sizeof(value));
-       OsalMemFree(pBuff,MAX_RW_SIZE);
+       kfree(pBuff);
 
        return Status;
 
@@ -1873,16 +1638,13 @@ INT PropagateCalParamsFromFlashToMemory(PMINI_ADAPTER Adapter)
                return -1;
        }
 
-       pBuff = OsalMemAlloc(uiEepromSize, 0);
-
+       pBuff = kmalloc(uiEepromSize, GFP_KERNEL);
        if ( pBuff == NULL )
-       {
                return -1;
-       }
 
        if(0 != BeceemNVMRead(Adapter,(PUINT)pBuff,uiCalStartAddr, uiEepromSize))
        {
-               OsalMemFree(pBuff, 0);
+               kfree(pBuff);
                return -1;
        }
 
@@ -1905,7 +1667,7 @@ INT PropagateCalParamsFromFlashToMemory(PMINI_ADAPTER Adapter)
                uiBytesToCopy = MIN(BUFFER_4K,uiEepromSize);
        }
 
-       OsalMemFree(pBuff, 0);
+       kfree(pBuff);
        return Status;
 
 }
@@ -1947,14 +1709,14 @@ static INT BeceemEEPROMReadBackandVerify(
                {// for the requests more than or equal to MAX_RW_SIZE bytes, use bulk read function to make the access faster.
                        BeceemEEPROMBulkRead(Adapter,&auiData[0],uiOffset,MAX_RW_SIZE);
 
-                       if(OsalMemCompare(&pBuffer[uiIndex],&auiData[0],MAX_RW_SIZE))
+                       if(memcmp(&pBuffer[uiIndex],&auiData[0],MAX_RW_SIZE))
                        {
                                // re-write
                                BeceemEEPROMBulkWrite(Adapter,(PUCHAR)(pBuffer+uiIndex),uiOffset,MAX_RW_SIZE,FALSE);
                                mdelay(3);
                                BeceemEEPROMBulkRead(Adapter,&auiData[0],uiOffset,MAX_RW_SIZE);
 
-                               if(OsalMemCompare(&pBuffer[uiIndex],&auiData[0],MAX_RW_SIZE))
+                               if(memcmp(&pBuffer[uiIndex],&auiData[0],MAX_RW_SIZE))
                                {
                                        return -1;
                                }
@@ -1986,7 +1748,7 @@ static INT BeceemEEPROMReadBackandVerify(
                else
                { // Handle the reads less than 4 bytes...
                        uiData = 0;
-                       OsalMemMove(&uiData,((PUCHAR)pBuffer)+(uiIndex*sizeof(UINT)),uiNumBytes);
+                       memcpy(&uiData,((PUCHAR)pBuffer)+(uiIndex*sizeof(UINT)),uiNumBytes);
                        BeceemEEPROMBulkRead(Adapter,&uiRdbk,uiOffset,4);
 
                        if(memcmp(&uiData, &uiRdbk, uiNumBytes))
@@ -2186,7 +1948,7 @@ INT BeceemEEPROMBulkWrite(
 
                if(uiBytesToCopy >= (16 -uiExtraBytes))
                {
-                       OsalMemMove((((PUCHAR)&uiData[0])+uiExtraBytes),pBuffer,MAX_RW_SIZE- uiExtraBytes);
+                       memcpy((((PUCHAR)&uiData[0])+uiExtraBytes),pBuffer,MAX_RW_SIZE- uiExtraBytes);
 
                        if ( STATUS_FAILURE == BeceemEEPROMWritePage( Adapter, uiData, uiTempOffset ) )
                                        return STATUS_FAILURE;
@@ -2197,7 +1959,7 @@ INT BeceemEEPROMBulkWrite(
                }
                else
                {
-                       OsalMemMove((((PUCHAR)&uiData[0])+uiExtraBytes),pBuffer,uiBytesToCopy);
+                       memcpy((((PUCHAR)&uiData[0])+uiExtraBytes),pBuffer,uiBytesToCopy);
 
                        if ( STATUS_FAILURE == BeceemEEPROMWritePage( Adapter, uiData, uiTempOffset ) )
                                        return STATUS_FAILURE;
@@ -2233,7 +1995,7 @@ INT BeceemEEPROMBulkWrite(
        // To program non 16byte aligned data, read 16byte and then update.
        //
                        BeceemEEPROMBulkRead(Adapter,&uiData[0],uiOffset,16);
-                       OsalMemMove(&uiData[0],pBuffer+uiIndex,uiBytesToCopy);
+                       memcpy(&uiData[0],pBuffer+uiIndex,uiBytesToCopy);
 
 
                        if ( STATUS_FAILURE == BeceemEEPROMWritePage( Adapter, uiData, uiOffset ) )
@@ -2535,7 +2297,7 @@ INT BcmUpdateSectorSize(PMINI_ADAPTER Adapter,UINT uiSectorSize)
 //
 //-----------------------------------------------------------------------------
 
-UINT BcmGetFlashSectorSize(PMINI_ADAPTER Adapter, UINT FlashSectorSizeSig, UINT FlashSectorSize)
+static UINT BcmGetFlashSectorSize(PMINI_ADAPTER Adapter, UINT FlashSectorSizeSig, UINT FlashSectorSize)
 {
        UINT uiSectorSize = 0;
        UINT uiSectorSig = 0;
@@ -2642,20 +2404,8 @@ static INT BcmInitEEPROMQueues(PMINI_ADAPTER Adapter)
 
 INT BcmInitNVM(PMINI_ADAPTER ps_adapter)
 {
-#ifdef BCM_SHM_INTERFACE
-#ifdef FLASH_DIRECT_ACCESS
-       unsigned int data,data1,data2 = 1;
-       wrm(ps_adapter, PAD_SELECT_REGISTER, &data2, 4);
-       data1 = rdm(ps_adapter,SYS_CFG,&data,4);
-       data1 = rdm(ps_adapter,SYS_CFG,&data,4);
-       data2 = (data | 0x80 | 0x8000);
-       wrm(ps_adapter,SYS_CFG, &data2,4); // over-write as Flash boot mode
-#endif
-       ps_adapter->eNVMType = NVM_FLASH;
-#else
        BcmValidateNvmType(ps_adapter);
        BcmInitEEPROMQueues(ps_adapter);
-#endif
 
        if(ps_adapter->eNVMType == NVM_AUTODETECT)
        {
@@ -2684,7 +2434,7 @@ INT BcmInitNVM(PMINI_ADAPTER ps_adapter)
 */
 /***************************************************************************/
 
-INT BcmGetNvmSize(PMINI_ADAPTER Adapter)
+static INT BcmGetNvmSize(PMINI_ADAPTER Adapter)
 {
        if(Adapter->eNVMType == NVM_EEPROM)
        {
@@ -2708,7 +2458,7 @@ INT BcmGetNvmSize(PMINI_ADAPTER Adapter)
 // Returns:
 //             <VOID>
 //-----------------------------------------------------------------------------
-VOID BcmValidateNvmType(PMINI_ADAPTER Adapter)
+static VOID BcmValidateNvmType(PMINI_ADAPTER Adapter)
 {
 
        //
@@ -2775,7 +2525,7 @@ INT BcmAllocFlashCSStructure(PMINI_ADAPTER psAdapter)
        if(psAdapter->psFlash2xCSInfo == NULL)
        {
                BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0,"Can't Allocate memory for Flash 2.x");
-               bcm_kfree(psAdapter->psFlashCSInfo);
+               kfree(psAdapter->psFlashCSInfo);
                return -ENOMEM;
        }
 
@@ -2783,8 +2533,8 @@ INT BcmAllocFlashCSStructure(PMINI_ADAPTER psAdapter)
        if(psAdapter->psFlash2xVendorInfo == NULL)
        {
                BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0,"Can't Allocate Vendor Info Memory for Flash 2.x");
-               bcm_kfree(psAdapter->psFlashCSInfo);
-               bcm_kfree(psAdapter->psFlash2xCSInfo);
+               kfree(psAdapter->psFlashCSInfo);
+               kfree(psAdapter->psFlash2xCSInfo);
                return -ENOMEM;
        }
 
@@ -2798,9 +2548,9 @@ INT BcmDeAllocFlashCSStructure(PMINI_ADAPTER psAdapter)
                BCM_DEBUG_PRINT(psAdapter,DBG_TYPE_PRINTK, 0, 0," Adapter structure point is NULL");
                return -EINVAL;
        }
-       bcm_kfree(psAdapter->psFlashCSInfo);
-       bcm_kfree(psAdapter->psFlash2xCSInfo);
-       bcm_kfree(psAdapter->psFlash2xVendorInfo);
+       kfree(psAdapter->psFlashCSInfo);
+       kfree(psAdapter->psFlash2xCSInfo);
+       kfree(psAdapter->psFlash2xVendorInfo);
        return STATUS_SUCCESS ;
 }
 
@@ -2954,7 +2704,7 @@ static INT        ConvertEndianOfCSStructure(PFLASH_CS_INFO psFlashCSInfo)
        return STATUS_SUCCESS;
 }
 
-INT IsSectionExistInVendorInfo(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section)
+static INT IsSectionExistInVendorInfo(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section)
 {
        return ( Adapter->uiVendorExtnFlag &&
                (Adapter->psFlash2xVendorInfo->VendorSection[section].AccessFlags & FLASH2X_SECTION_PRESENT) &&
@@ -3052,7 +2802,7 @@ static VOID UpdateVendorInfo(PMINI_ADAPTER Adapter)
 //             <VOID>
 //-----------------------------------------------------------------------------
 
-INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter)
+static INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter)
 {
        //FLASH_CS_INFO sFlashCsInfo = {0};
 
@@ -3070,7 +2820,6 @@ INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter)
        memset(Adapter->psFlashCSInfo, 0 ,sizeof(FLASH_CS_INFO));
        memset(Adapter->psFlash2xCSInfo, 0 ,sizeof(FLASH2X_CS_INFO));
 
-#ifndef BCM_SHM_INTERFACE
        if(!Adapter->bDDRInitDone)
        {
                {
@@ -3079,7 +2828,6 @@ INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter)
                }
        }
 
-#endif
 
        // Reading first 8 Bytes to get the Flash Layout
        // MagicNumber(4 bytes) +FlashLayoutMinorVersion(2 Bytes) +FlashLayoutMajorVersion(2 Bytes)
@@ -3147,9 +2895,7 @@ INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter)
                        return STATUS_FAILURE;
                }
                ConvertEndianOf2XCSStructure(Adapter->psFlash2xCSInfo);
-#ifndef BCM_SHM_INTERFACE
                BcmDumpFlash2XCSStructure(Adapter->psFlash2xCSInfo,Adapter);
-#endif
                if((FLASH_CONTROL_STRUCT_SIGNATURE == Adapter->psFlash2xCSInfo->MagicNumber) &&
                   (SCSI_FIRMWARE_MINOR_VERSION <= MINOR_VERSION(Adapter->psFlash2xCSInfo->SCSIFirmwareVersion)) &&
                   (FLASH_SECTOR_SIZE_SIG == Adapter->psFlash2xCSInfo->FlashSectorSizeSig) &&
@@ -3181,21 +2927,10 @@ INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter)
        Concerns: what if CS sector size does not match with this sector size ???
        what is the indication of AccessBitMap  in CS in flash 2.x ????
        */
-#ifndef BCM_SHM_INTERFACE
        Adapter->ulFlashID = BcmReadFlashRDID(Adapter);
-#endif
 
        Adapter->uiFlashLayoutMajorVersion = uiFlashLayoutMajorVersion;
 
-       #if 0
-       if(FLASH_PART_SST25VF080B == Adapter->ulFlashID)
-       {
-       //
-       // 1MB flash has been selected. we have to use 64K as sector size no matter what is kept in FLASH_CS.
-       //
-               Adapter->uiSectorSize = 0x10000;
-       }
-       #endif
 
        return STATUS_SUCCESS ;
 }
@@ -3214,7 +2949,7 @@ INT BcmGetFlashCSInfo(PMINI_ADAPTER Adapter)
 //
 //-----------------------------------------------------------------------------
 
-NVM_TYPE BcmGetNvmType(PMINI_ADAPTER Adapter)
+static NVM_TYPE BcmGetNvmType(PMINI_ADAPTER Adapter)
 {
        UINT uiData = 0;
 
@@ -3568,39 +3303,6 @@ INT BcmFlash2xBulkWrite(
 
 }
 
-/**
-*      ReadDSDHeader : Read the DSD map for the DSD Section val provided in Argument.
-*      @Adapter : Beceem Private Data Structure
-*      @psDSDHeader :Pointer of the buffer where header has to be read
-*      @dsd :value of the Dyanmic DSD like DSD0 of DSD1 or DSD2
-*
-*      Return Value:-
-*              if suceeds return STATUS_SUCCESS or negative error code.
-**/
-INT ReadDSDHeader(PMINI_ADAPTER Adapter, PDSD_HEADER psDSDHeader, FLASH2X_SECTION_VAL dsd)
-{
-       INT Status = STATUS_SUCCESS;
-
-       Status =BcmFlash2xBulkRead(Adapter,
-                                                   (PUINT)psDSDHeader,
-                                                       dsd,
-                                                       Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader,
-                                                       sizeof(DSD_HEADER));
-       if(Status == STATUS_SUCCESS)
-       {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSDImageMagicNumber :0X%x", ntohl(psDSDHeader->DSDImageMagicNumber));
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSDImageSize :0X%x ",ntohl(psDSDHeader->DSDImageSize));
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSDImageCRC :0X%x",ntohl(psDSDHeader->DSDImageCRC));
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSDImagePriority :0X%x",ntohl(psDSDHeader->DSDImagePriority));
-       }
-       else
-       {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"DSD Header read is failed with status :%d", Status);
-       }
-
-       return Status;
-}
-
 /**
 *      BcmGetActiveDSD : Set the Active DSD in Adapter Structure which has to be dumped in DDR
 *      @Adapter :-Drivers private Data Structure
@@ -3609,7 +3311,7 @@ INT ReadDSDHeader(PMINI_ADAPTER Adapter, PDSD_HEADER psDSDHeader, FLASH2X_SECTIO
 *              Return STATUS_SUCESS if get sucess in setting the right DSD else negaive error code
 *
 **/
-INT BcmGetActiveDSD(PMINI_ADAPTER Adapter)
+static INT BcmGetActiveDSD(PMINI_ADAPTER Adapter)
 {
        FLASH2X_SECTION_VAL uiHighestPriDSD = 0 ;
 
@@ -3647,39 +3349,6 @@ INT BcmGetActiveDSD(PMINI_ADAPTER Adapter)
        return STATUS_SUCCESS;
 }
 
-/**
-*      ReadISOUnReservedBytes : Read the ISO map for the ISO Section val provided in Argument.
-*      @Adapter : Driver Private Data Structure
-*      @psISOHeader :Pointer of the location where header has to be read
-*      @IsoImage :value of the Dyanmic ISO like ISO_IMAGE1 of ISO_IMAGE2
-*
-*      Return Value:-
-*              if suceeds return STATUS_SUCCESS or negative error code.
-**/
-
-INT ReadISOHeader(PMINI_ADAPTER Adapter, PISO_HEADER psISOHeader, FLASH2X_SECTION_VAL IsoImage)
-{
-       INT Status = STATUS_SUCCESS;
-
-       Status = BcmFlash2xBulkRead(Adapter,
-                                           (PUINT)psISOHeader,
-                                               IsoImage,
-                                               0,
-                                               sizeof(ISO_HEADER));
-
-       if(Status == STATUS_SUCCESS)
-       {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISOImageMagicNumber :0X%x", ntohl(psISOHeader->ISOImageMagicNumber));
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISOImageSize :0X%x ",ntohl(psISOHeader->ISOImageSize));
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISOImageCRC :0X%x",ntohl(psISOHeader->ISOImageCRC));
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISOImagePriority :0X%x",ntohl(psISOHeader->ISOImagePriority));
-       }
-       else
-       {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "ISO Header Read failed");
-       }
-       return Status;
-}
 
 /**
 *      BcmGetActiveISO :- Set the Active ISO in Adapter Data Structue
@@ -3691,7 +3360,7 @@ INT ReadISOHeader(PMINI_ADAPTER Adapter, PISO_HEADER psISOHeader, FLASH2X_SECTIO
 *
 **/
 
-INT BcmGetActiveISO(PMINI_ADAPTER Adapter)
+static INT BcmGetActiveISO(PMINI_ADAPTER Adapter)
 {
 
        INT HighestPriISO = 0 ;
@@ -4588,7 +4257,7 @@ INT BcmCopyISO(PMINI_ADAPTER Adapter, FLASH2X_COPY_SECTION sCopySectStrut)
 
        }
 
-       bcm_kfree(Buff);
+       kfree(Buff);
 
        return Status;
 }
@@ -4789,7 +4458,7 @@ Return Value:-
        Success :- Base Address of the Flash
 **/
 
-INT GetFlashBaseAddr(PMINI_ADAPTER Adapter)
+static INT GetFlashBaseAddr(PMINI_ADAPTER Adapter)
 {
 
        UINT uiBaseAddr = 0;
@@ -4866,20 +4535,6 @@ INT      BcmCopySection(PMINI_ADAPTER Adapter,
                return  -EINVAL;
        }
 
-       #if 0
-       else
-       {
-               if((SrcSection == VSA0) || (SrcSection == VSA1) || (SrcSection == VSA2))
-               {
-                       if((DstSection != VSA0) && (DstSection != VSA1) && (DstSection != VSA2))
-                       {
-                               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Source and Destion secton is not of same type");
-                               return -EINVAL;
-                       }
-               }
-
-       }
-       #endif
        //if offset zero means have to copy complete secton
 
        if(numOfBytes == 0)
@@ -4954,7 +4609,7 @@ INT       BcmCopySection(PMINI_ADAPTER Adapter,
                                BytesToBeCopied = numOfBytes;
                }
        }while(numOfBytes > 0) ;
-       bcm_kfree(pBuff);
+       kfree(pBuff);
        Adapter->bHeaderChangeAllowed = FALSE ;
        return Status;
 }
@@ -4979,14 +4634,6 @@ INT SaveHeaderIfPresent(PMINI_ADAPTER Adapter, PUCHAR pBuff, UINT uiOffset)
        UINT uiSectAlignAddr = 0;
        UINT sig = 0;
 
-       #if 0
-       //if Chenges in Header is allowed, Return back
-       if(Adapter->bHeaderChangeAllowed == TRUE)
-       {
-               BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Header Change is allowed");
-               return STATUS_SUCCESS ;
-       }
-       #endif
        //making the offset sector alligned
        uiSectAlignAddr = uiOffset & ~(Adapter->uiSectorSize - 1);
 
@@ -5024,7 +4671,7 @@ INT SaveHeaderIfPresent(PMINI_ADAPTER Adapter, PUCHAR pBuff, UINT uiOffset)
                //Replace Buffer content with Header
                memcpy(pBuff +offsetToProtect,pTempBuff,HeaderSizeToProtect);
 
-               bcm_kfree(pTempBuff);
+               kfree(pTempBuff);
        }
        if(bHasHeader && Adapter->bSigCorrupted)
        {
@@ -5044,29 +4691,7 @@ INT SaveHeaderIfPresent(PMINI_ADAPTER Adapter, PUCHAR pBuff, UINT uiOffset)
 
        return STATUS_SUCCESS ;
 }
-INT BcmMakeFlashCSActive(PMINI_ADAPTER Adapter, UINT offset)
-{
-       UINT GPIOConfig = 0 ;
-
-
-       if(Adapter->bFlashRawRead == FALSE)
-       {
-               //Applicable for Flash2.x
-               if(IsFlash2x(Adapter) == FALSE)
-                       return STATUS_SUCCESS;
-       }
 
-       if(offset/FLASH_PART_SIZE)
-       {
-               //bit[14..12] -> will select make Active CS1, CS2 or CS3
-               // Select CS1, CS2 and CS3 (CS0 is dedicated pin)
-               rdmalt(Adapter,FLASH_GPIO_CONFIG_REG, &GPIOConfig, 4);
-               GPIOConfig |= (7 << 12);
-               wrmalt(Adapter,FLASH_GPIO_CONFIG_REG, &GPIOConfig, 4);
-       }
-
-       return STATUS_SUCCESS ;
-}
 /**
 BcmDoChipSelect : This will selcet the appropriate chip for writing.
 @Adapater :- Bcm Driver Private Data Structure
@@ -5074,7 +4699,7 @@ BcmDoChipSelect : This will selcet the appropriate chip for writing.
 OutPut:-
        Select the Appropriate chip and retrn status Sucess
 **/
-INT BcmDoChipSelect(PMINI_ADAPTER Adapter, UINT offset)
+static INT BcmDoChipSelect(PMINI_ADAPTER Adapter, UINT offset)
 {
        UINT FlashConfig = 0;
        INT ChipNum = 0;
@@ -5365,39 +4990,6 @@ INT WriteToFlashWithoutSectorErase(PMINI_ADAPTER Adapter,
        return Status;
 }
 
-#if 0
-UINT getNumOfSubSectionWithWRPermisson(PMINI_ADAPTER Adapter, SECTION_TYPE secType)
-{
-
-       UINT numOfWRSubSec = 0;
-       switch(secType)
-       {
-               case ISO :
-                       if(IsSectionWritable(Adapter,ISO_IMAGE1))
-                               numOfWRSubSec = numOfWRSubSec + 1;
-                       if(IsSectionWritable(Adapter,ISO_IMAGE2))
-                               numOfWRSubSec = numOfWRSubSec + 1;
-                       break;
-
-               case DSD :
-                       if(IsSectionWritable(Adapter,DSD2))
-                               numOfWRSubSec = numOfWRSubSec + 1;
-                       if(IsSectionWritable(Adapter,DSD1))
-                               numOfWRSubSec = numOfWRSubSec + 1;
-                       if(IsSectionWritable(Adapter,DSD0))
-                               numOfWRSubSec = numOfWRSubSec + 1;
-                       break ;
-
-               case VSA :
-                               //for VSA Add code Here
-                default :
-                       BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Invalid secton<%d> is passed", secType);\
-                       numOfWRSubSec = 0;
-
-       }
-       return numOfWRSubSec;
-}
-#endif
 BOOLEAN IsSectionExistInFlash(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL section)
 {
 
@@ -5479,7 +5071,7 @@ INT IsSectionWritable(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL Section)
                return Status ;
 }
 
-INT CorruptDSDSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
+static INT CorruptDSDSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
 {
 
        PUCHAR pBuff = NULL;
@@ -5543,16 +5135,16 @@ INT CorruptDSDSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
        else
        {
                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"BCM Signature is not present in header");
-               bcm_kfree(pBuff);
+               kfree(pBuff);
                return STATUS_FAILURE;
        }
 
-       bcm_kfree(pBuff);
+       kfree(pBuff);
        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Corrupted the signature");
        return STATUS_SUCCESS ;
 }
 
-INT CorruptISOSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
+static INT CorruptISOSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
 {
 
        PUCHAR pBuff = NULL;
@@ -5593,14 +5185,14 @@ INT CorruptISOSig(PMINI_ADAPTER Adapter, FLASH2X_SECTION_VAL eFlash2xSectionVal)
        else
        {
                BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"BCM Signature is not present in header");
-               bcm_kfree(pBuff);
+               kfree(pBuff);
                return STATUS_FAILURE;
        }
 
        BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,"Corrupted the signature");
        BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL,pBuff,MAX_RW_SIZE);
 
-       bcm_kfree(pBuff);
+       kfree(pBuff);
        return STATUS_SUCCESS ;
 }
 
index 6ec6ca85b501482801abbf39ec7a7dbe0231f49f..651b5a455b32aea6dce65165604068adf75c2227 100644 (file)
@@ -323,15 +323,6 @@ typedef struct _ISO_HEADER
 
 
 
-#ifdef BCM_SHM_INTERFACE
-
-#define FLASH_ADDR_MASK                          0x1F000000
-extern int bcmflash_raw_read(unsigned int flash_id, unsigned int offset, unsigned char *inbuf, unsigned int len);
-extern int bcmflash_raw_write(unsigned int flash_id, unsigned int offset, unsigned char *outbuf, unsigned int len);
-extern int bcmflash_raw_writenoerase(unsigned int flash_id, unsigned int offset, unsigned char *outbuf, unsigned int len);
-
-
-#endif
 
 #define FLASH_CONTIGIOUS_START_ADDR_AFTER_INIT   0x1C000000
 #define FLASH_CONTIGIOUS_START_ADDR_BEFORE_INIT  0x1F000000
@@ -414,76 +405,5 @@ extern int bcmflash_raw_writenoerase(unsigned int flash_id, unsigned int offset,
 
 #define FIELD_OFFSET_IN_HEADER(HeaderPointer,Field) ((PUCHAR)&((HeaderPointer)(NULL))->Field - (PUCHAR)(NULL))
 
-#if 0
-INT BeceemEEPROMBulkRead(
-       PMINI_ADAPTER Adapter,
-       PUINT pBuffer,
-       UINT uiOffset,
-       UINT uiNumBytes);
-
-
-INT BeceemFlashBulkRead(
-       PMINI_ADAPTER Adapter,
-       PUINT pBuffer,
-       UINT uiOffset,
-       UINT uiNumBytes);
-
-UINT BcmGetEEPROMSize(PMINI_ADAPTER Adapter);
-
-UINT BcmGetFlashSize(PMINI_ADAPTER Adapter);
-
-UINT BcmGetFlashSectorSize(PMINI_ADAPTER Adapter);
-
-
-
-INT BeceemFlashBulkWrite(
-       PMINI_ADAPTER Adapter,
-       PUINT pBuffer,
-       UINT uiOffset,
-       UINT uiNumBytes,
-       BOOLEAN bVerify);
-
-INT PropagateCalParamsFromFlashToMemory(PMINI_ADAPTER Adapter);
-
-INT PropagateCalParamsFromEEPROMToMemory(PMINI_ADAPTER Adapter);
-
-
-INT BeceemEEPROMBulkWrite(
-       PMINI_ADAPTER Adapter,
-       PUCHAR pBuffer,
-       UINT uiOffset,
-       UINT uiNumBytes,
-       BOOLEAN bVerify);
-
-
-INT ReadBeceemEEPROM(PMINI_ADAPTER Adapter,UINT dwAddress, UINT *pdwData);
-
-NVM_TYPE BcmGetNvmType(PMINI_ADAPTER Adapter);
-
-INT BeceemNVMRead(
-       PMINI_ADAPTER Adapter,
-       PUINT pBuffer,
-       UINT uiOffset,
-       UINT uiNumBytes);
-
-INT BeceemNVMWrite(
-       PMINI_ADAPTER Adapter,
-       PUINT pBuffer,
-       UINT uiOffset,
-       UINT uiNumBytes,
-       BOOLEAN bVerify);
-
-INT ReadMacAddressFromEEPROM(PMINI_ADAPTER Adapter);
-
-INT BcmUpdateSectorSize(PMINI_ADAPTER Adapter,UINT uiSectorSize);
-
-INT BcmInitNVM(PMINI_ADAPTER Adapter);
-
-VOID BcmValidateNvmType(PMINI_ADAPTER Adapter);
-
-VOID BcmGetFlashCSInfo(PMINI_ADAPTER Adapter);
-
-#endif
-
 #endif
 
diff --git a/drivers/staging/bcm/osal_misc.h b/drivers/staging/bcm/osal_misc.h
deleted file mode 100644 (file)
index ff4adde..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-       /*++
-
-       Copyright (c) Beceem Communications Inc.
-
-       Module Name:
-               OSAL_Misc.h
-
-       Abstract:
-               Provides the OS Abstracted macros to access:
-                       Linked Lists
-                       Dispatcher Objects(Events,Semaphores,Spin Locks and the like)
-                       Files
-
-
-       Revision History:
-               Who         When        What
-               --------    --------    ----------------------------------------------
-               Name            Date            Created/reviewed/modified
-               Rajeev          24/1/08         Created
-       Notes:
-
-       --*/
-#ifndef _OSAL_MISC_H_
-#define _OSAL_MISC_H_
-//OSAL Macros
-//OSAL Primitives
-typedef PUCHAR  POSAL_NW_PACKET  ;             //Nw packets
-
-
-#define OsalMemAlloc(n,t) kmalloc(n,GFP_KERNEL)
-
-#define OsalMemFree(x,n) bcm_kfree(x)
-
-#define OsalMemMove(dest, src, len)            \
-{                                                                              \
-                       memcpy(dest,src, len);          \
-}
-
-#define OsalZeroMemory(pDest, Len)             \
-{                                                                              \
-                       memset(pDest,0,Len);            \
-}
-
-//#define OsalMemSet(pSrc,Char,Len) memset(pSrc,Char,Len)
-
-bool OsalMemCompare(void *dest, void *src, UINT len);
-
-#endif
-
index 4c613da3553ab11824bdd02cdb54fa1422fcc1de..6738983e2d5ca34a8483c443a9c898f128e49f74 100644 (file)
 /* ****************** BCMSDH Interface Functions *************************** */
 
 #include <linux/types.h>
+#include <linux/netdevice.h>
 #include <bcmdefs.h>
 #include <bcmdevs.h>
 #include <bcmendian.h>
+#include <osl.h>
 #include <bcmutils.h>
 #include <hndsoc.h>
 #include <siutils.h>
-#include <osl.h>
 
 #include <bcmsdh.h>            /* BRCM API for SDIO
                         clients (such as wl, dhd) */
index 9028cd01d9d03fdfdbf1feb6248d02b2d8c57197..be33696b8f74d3720c496ff4511c02345160bbbd 100644 (file)
@@ -20,8 +20,7 @@
 
 #define __UNDEF_NO_VERSION__
 
-#include <linuxver.h>
-
+#include <linux/netdevice.h>
 #include <linux/pci.h>
 #include <linux/completion.h>
 
@@ -189,7 +188,7 @@ int bcmsdh_probe(struct device *dev)
        }
 #endif                         /* defined(OOB_INTR_ONLY) */
        /* allocate SDIO Host Controller state info */
-       osh = osl_attach(dev, PCI_BUS, false);
+       osh = osl_attach(dev, PCI_BUS);
        if (!osh) {
                SDLX_MSG(("%s: osl_attach failed\n", __func__));
                goto err;
@@ -385,7 +384,7 @@ bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
                SDLX_MSG(("%s: Disabling TI FlashMedia Controller.\n",
                          __func__));
-               osh = osl_attach(pdev, PCI_BUS, false);
+               osh = osl_attach(pdev, PCI_BUS);
                if (!osh) {
                        SDLX_MSG(("%s: osl_attach failed\n", __func__));
                        goto err;
@@ -420,7 +419,7 @@ bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
         */
 
        /* allocate SDIO Host Controller state info */
-       osh = osl_attach(pdev, PCI_BUS, false);
+       osh = osl_attach(pdev, PCI_BUS);
        if (!osh) {
                SDLX_MSG(("%s: osl_attach failed\n", __func__));
                goto err;
index f6c9c454181328b139e419b3f9110ed838341b11..039f114130d23774f93aa3cc4bf418992d02177f 100644 (file)
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 #include <linux/types.h>
+#include <linux/netdevice.h>
 #include <bcmdefs.h>
 #include <bcmdevs.h>
 #include <bcmendian.h>
-#include <bcmutils.h>
 #include <osl.h>
+#include <bcmutils.h>
 #include <sdio.h>              /* SDIO Device and Protocol Specs */
 #include <sdioh.h>             /* SDIO Host Controller Specification */
 #include <bcmsdbus.h>          /* bcmsdh to/from specific controller APIs */
index ae7b566b11d70227ddb323002306e44b52fb4bf9..14f73fd287605ad57583bd54dd1feb6469b021f7 100644 (file)
@@ -15,7 +15,9 @@
  */
 #include <linux/types.h>
 #include <linux/sched.h>       /* request_irq() */
+#include <linux/netdevice.h>
 #include <bcmdefs.h>
+#include <osl.h>
 #include <bcmutils.h>
 #include <sdio.h>              /* SDIO Specs */
 #include <bcmsdbus.h>          /* bcmsdh to/from specific controller APIs */
index bcbaac9bcdcc8af209b28a10463dd2710679efdb..0d14f6c1fcfa6b83224bf128ba0b2002f6c49ecc 100644 (file)
@@ -15,6 +15,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/netdevice.h>
 #include <bcmdefs.h>
 #include <osl.h>
 
index 703188fc28ec9f26a87b6aeed82ac6d5f720580b..f7ffea69233c74cd6783827ec6eeaff133da3277 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <bcmdefs.h>
+#include <linux/netdevice.h>
 #include <osl.h>
 #include <bcmutils.h>
 #include <bcmendian.h>
index f647034f36d689348024a48d4e0daf673fc416f4..bb3c7b8c4b982e925a480b31617341e2b23bd183 100644 (file)
@@ -14,7 +14,7 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <linuxver.h>
+#include <linux/netdevice.h>
 #include <osl.h>
 #include <bcmutils.h>
 
index bbbe7c5f7492573508d5027b03cd1df9a187b561..d7ad3e44dd78890b39a1f5c9b63459ea33166f44 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/fs.h>
 #include <linux/uaccess.h>
 #include <bcmdefs.h>
-#include <linuxver.h>
 #include <osl.h>
 #include <bcmutils.h>
 #include <bcmendian.h>
@@ -1190,7 +1189,7 @@ void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt)
                /* Process special event packets and then discard them */
                if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM)
                        dhd_wl_host_event(dhd, &ifidx,
-                                         skb->mac_header,
+                                         skb_mac_header(skb),
                                          &event, &data);
 
                ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]);
@@ -1621,6 +1620,51 @@ static int dhd_ethtool(dhd_info_t *dhd, void *uaddr)
        return 0;
 }
 
+static s16 linuxbcmerrormap[] = { 0,   /* 0 */
+       -EINVAL,                /* BCME_ERROR */
+       -EINVAL,                /* BCME_BADARG */
+       -EINVAL,                /* BCME_BADOPTION */
+       -EINVAL,                /* BCME_NOTUP */
+       -EINVAL,                /* BCME_NOTDOWN */
+       -EINVAL,                /* BCME_NOTAP */
+       -EINVAL,                /* BCME_NOTSTA */
+       -EINVAL,                /* BCME_BADKEYIDX */
+       -EINVAL,                /* BCME_RADIOOFF */
+       -EINVAL,                /* BCME_NOTBANDLOCKED */
+       -EINVAL,                /* BCME_NOCLK */
+       -EINVAL,                /* BCME_BADRATESET */
+       -EINVAL,                /* BCME_BADBAND */
+       -E2BIG,                 /* BCME_BUFTOOSHORT */
+       -E2BIG,                 /* BCME_BUFTOOLONG */
+       -EBUSY,                 /* BCME_BUSY */
+       -EINVAL,                /* BCME_NOTASSOCIATED */
+       -EINVAL,                /* BCME_BADSSIDLEN */
+       -EINVAL,                /* BCME_OUTOFRANGECHAN */
+       -EINVAL,                /* BCME_BADCHAN */
+       -EFAULT,                /* BCME_BADADDR */
+       -ENOMEM,                /* BCME_NORESOURCE */
+       -EOPNOTSUPP,            /* BCME_UNSUPPORTED */
+       -EMSGSIZE,              /* BCME_BADLENGTH */
+       -EINVAL,                /* BCME_NOTREADY */
+       -EPERM,                 /* BCME_NOTPERMITTED */
+       -ENOMEM,                /* BCME_NOMEM */
+       -EINVAL,                /* BCME_ASSOCIATED */
+       -ERANGE,                /* BCME_RANGE */
+       -EINVAL,                /* BCME_NOTFOUND */
+       -EINVAL,                /* BCME_WME_NOT_ENABLED */
+       -EINVAL,                /* BCME_TSPEC_NOTFOUND */
+       -EINVAL,                /* BCME_ACM_NOTSUPPORTED */
+       -EINVAL,                /* BCME_NOT_WME_ASSOCIATION */
+       -EIO,                   /* BCME_SDIO_ERROR */
+       -ENODEV,                /* BCME_DONGLE_DOWN */
+       -EINVAL,                /* BCME_VERSION */
+       -EIO,                   /* BCME_TXFAIL */
+       -EIO,                   /* BCME_RXFAIL */
+       -EINVAL,                /* BCME_NODEVICE */
+       -EINVAL,                /* BCME_NMODE_DISABLED */
+       -ENODATA,               /* BCME_NONRESIDENT */
+};
+
 static int dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
 {
        dhd_info_t *dhd = *(dhd_info_t **) netdev_priv(net);
@@ -1742,7 +1786,12 @@ done:
        if (buf)
                kfree(buf);
 
-       return OSL_ERROR(bcmerror);
+       if (bcmerror > 0)
+               bcmerror = 0;
+       else if (bcmerror < BCME_LAST)
+               bcmerror = BCME_ERROR;
+
+       return linuxbcmerrormap[-bcmerror];
 }
 
 static int dhd_stop(struct net_device *net)
@@ -1816,7 +1865,7 @@ static int dhd_open(struct net_device *net)
 
 osl_t *dhd_osl_attach(void *pdev, uint bustype)
 {
-       return osl_attach(pdev, bustype, true);
+       return osl_attach(pdev, bustype);
 }
 
 void dhd_osl_detach(osl_t *osh)
index bf8df9801030e20fa06bb556d2470bd091c2f8b4..c66f1c2941e2865bcc0ba0a2fa21b51ab8a772e9 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/sched.h>
-#include <linuxver.h>
 
 int setScheduler(struct task_struct *p, int policy, struct sched_param *param)
 {
index b2281d9dfdcfa2d09afbc9052f548ef433cf0a74..66884d47e83465fe0bc17021bb752a980c1fe278 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/types.h>
 #include <bcmdefs.h>
+#include <linux/netdevice.h>
 #include <osl.h>
 #include <bcmsdh.h>
 
index 3f29488d9c7279c6ba79ad604d6fbb22b9a59a5a..6433a9241b4ee82cc2f34e18e064a9fa7842374d 100644 (file)
@@ -16,7 +16,6 @@
 
 #include <linux/kernel.h>
 #include <linux/if_arp.h>
-#include <linuxver.h>
 #include <osl.h>
 
 #include <bcmutils.h>
@@ -705,7 +704,7 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct wlc_ssid *ssid, u16 action)
 
        if (ssid && ssid->SSID_len)
                params_size += sizeof(struct wlc_ssid);
-       params = (struct wl_iscan_params *)kzalloc(params_size, GFP_KERNEL);
+       params = kzalloc(params_size, GFP_KERNEL);
        if (unlikely(!params))
                return -ENOMEM;
        memset(params, 0, params_size);
@@ -2794,53 +2793,52 @@ static void wl_init_eloop_handler(struct wl_event_loop *el)
 
 static s32 wl_init_priv_mem(struct wl_priv *wl)
 {
-       wl->scan_results = (void *)kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
+       wl->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
        if (unlikely(!wl->scan_results)) {
                WL_ERR(("Scan results alloc failed\n"));
                goto init_priv_mem_out;
        }
-       wl->conf = (void *)kzalloc(sizeof(*wl->conf), GFP_KERNEL);
+       wl->conf = kzalloc(sizeof(*wl->conf), GFP_KERNEL);
        if (unlikely(!wl->conf)) {
                WL_ERR(("wl_conf alloc failed\n"));
                goto init_priv_mem_out;
        }
-       wl->profile = (void *)kzalloc(sizeof(*wl->profile), GFP_KERNEL);
+       wl->profile = kzalloc(sizeof(*wl->profile), GFP_KERNEL);
        if (unlikely(!wl->profile)) {
                WL_ERR(("wl_profile alloc failed\n"));
                goto init_priv_mem_out;
        }
-       wl->bss_info = (void *)kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
+       wl->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
        if (unlikely(!wl->bss_info)) {
                WL_ERR(("Bss information alloc failed\n"));
                goto init_priv_mem_out;
        }
-       wl->scan_req_int =
-           (void *)kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL);
+       wl->scan_req_int = kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL);
        if (unlikely(!wl->scan_req_int)) {
                WL_ERR(("Scan req alloc failed\n"));
                goto init_priv_mem_out;
        }
-       wl->ioctl_buf = (void *)kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL);
+       wl->ioctl_buf = kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL);
        if (unlikely(!wl->ioctl_buf)) {
                WL_ERR(("Ioctl buf alloc failed\n"));
                goto init_priv_mem_out;
        }
-       wl->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
+       wl->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
        if (unlikely(!wl->extra_buf)) {
                WL_ERR(("Extra buf alloc failed\n"));
                goto init_priv_mem_out;
        }
-       wl->iscan = (void *)kzalloc(sizeof(*wl->iscan), GFP_KERNEL);
+       wl->iscan = kzalloc(sizeof(*wl->iscan), GFP_KERNEL);
        if (unlikely(!wl->iscan)) {
                WL_ERR(("Iscan buf alloc failed\n"));
                goto init_priv_mem_out;
        }
-       wl->fw = (void *)kzalloc(sizeof(*wl->fw), GFP_KERNEL);
+       wl->fw = kzalloc(sizeof(*wl->fw), GFP_KERNEL);
        if (unlikely(!wl->fw)) {
                WL_ERR(("fw object alloc failed\n"));
                goto init_priv_mem_out;
        }
-       wl->pmk_list = (void *)kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL);
+       wl->pmk_list = kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL);
        if (unlikely(!wl->pmk_list)) {
                WL_ERR(("pmk list alloc failed\n"));
                goto init_priv_mem_out;
index 979a494fda59eaff5b23c5464bff79cd07096b07..d583b9d65d3567574f0cb16887d814972f25e042 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <linux/kthread.h>
 #include <bcmdefs.h>
-#include <linuxver.h>
+#include <linux/netdevice.h>
 #include <osl.h>
 #include <wlioctl.h>
 
@@ -3690,8 +3690,7 @@ int wl_iw_attach(struct net_device *dev, void *dhdp)
                return -ENOMEM;
        memset(iscan, 0, sizeof(iscan_info_t));
 
-       iscan->iscan_ex_params_p =
-           (wl_iscan_params_t *) kmalloc(params_size, GFP_KERNEL);
+       iscan->iscan_ex_params_p = kmalloc(params_size, GFP_KERNEL);
        if (!iscan->iscan_ex_params_p)
                return -ENOMEM;
        iscan->iscan_ex_param_size = params_size;
@@ -3723,9 +3722,7 @@ int wl_iw_attach(struct net_device *dev, void *dhdp)
        priv_dev = dev;
        MUTEX_LOCK_SOFTAP_SET_INIT(iw->pub);
 #endif
-       g_scan = NULL;
-
-       g_scan = (void *)kmalloc(G_SCAN_RESULTS, GFP_KERNEL);
+       g_scan = kmalloc(G_SCAN_RESULTS, GFP_KERNEL);
        if (!g_scan)
                return -ENOMEM;
 
index dc52e9dbb8b5ac2178c7a869b4ff7e7fba42b15e..ae6a65a6471441819c226c1e4cb5b4ad3cebb2c5 100644 (file)
@@ -42,9 +42,6 @@
 #define BCMFASTPATH
 #endif
 
-/* Put some library data/code into ROM to reduce RAM requirements */
-#define BCMROMFN(_fn)          _fn
-
 /* Bus types */
 #define        SI_BUS                  0       /* SOC Interconnect */
 #define        PCI_BUS                 1       /* PCI target */
 #define SPI_BUS                        6       /* gSPI target */
 #define RPC_BUS                        7       /* RPC target */
 
-/* Allows size optimization for single-bus image */
-#ifdef BCMBUSTYPE
-#define BUSTYPE(bus)   (BCMBUSTYPE)
-#else
 #define BUSTYPE(bus)   (bus)
-#endif
-
-/* Allows size optimization for single-backplane image */
-#ifdef BCMCHIPTYPE
-#define CHIPTYPE(bus)  (BCMCHIPTYPE)
-#else
 #define CHIPTYPE(bus)  (bus)
-#endif
-
-/* Allows size optimization for SPROM support */
-#define SPROMBUS       (PCI_BUS)
-
-/* Allows size optimization for single-chip image */
-#ifdef BCMCHIPID
-#define CHIPID(chip)   (BCMCHIPID)
-#else
 #define CHIPID(chip)   (chip)
-#endif
-
-#ifdef BCMCHIPREV
-#define CHIPREV(rev)   (BCMCHIPREV)
-#else
 #define CHIPREV(rev)   (rev)
-#endif
 
 /* Defines for DMA Address Width - Shared between OSL and HNDDMA */
 #define DMADDR_MASK_32 0x0     /* Address mask for 32-bits */
@@ -146,31 +118,11 @@ typedef struct {
 
 #define BCMEXTRAHDROOM 172
 
-/* Headroom required for dongle-to-host communication.  Packets allocated
- * locally in the dongle (e.g. for CDC ioctls or RNDIS messages) should
- * leave this much room in front for low-level message headers which may
- * be needed to get across the dongle bus to the host.  (These messages
- * don't go over the network, so room for the full WL header above would
- * be a waste.).
-*/
-#define BCMDONGLEHDRSZ 12
-#define BCMDONGLEPADSZ 16
-
-#define BCMDONGLEOVERHEAD      (BCMDONGLEHDRSZ + BCMDONGLEPADSZ)
-
 #ifdef BCMDBG
-
-#define BCMDBG_ERR
-
 #ifndef BCMDBG_ASSERT
 #define BCMDBG_ASSERT
-#endif                         /* BCMDBG_ASSERT */
-
-#endif                         /* BCMDBG */
-
-#if defined(BCMDBG_ASSERT)
-#define BCMASSERT_SUPPORT
-#endif
+#endif /* BCMDBG_ASSERT */
+#endif /* BCMDBG */
 
 /* Macros for doing definition and get/set of bitfields
  * Usage example, e.g. a three-bit field (bits 4-6):
@@ -190,10 +142,6 @@ typedef struct {
                (((val) & (~(field ## _M << field ## _S))) | \
                 ((unsigned)(bits) << field ## _S))
 
-/* define BCMSMALL to remove misc features for memory-constrained environments */
-#define        BCMSPACE
-#define bcmspace       true    /* if (bcmspace) code is retained */
-
 /* Max. nvram variable table size */
 #define        MAXSZ_NVRAM_VARS        4096
 
index b53315981be09ff8f38879d756819255f0a08a65..7f1d33481ee83a53201e01e4c6c3991a71d9ba0f 100644 (file)
@@ -30,7 +30,6 @@
        };
 
 /* ** driver-only section ** */
-#include <osl.h>
 
 #define GPIO_PIN_NOTDEFINED    0x20    /* Pin not defined */
 
index c07548c70e307dde7d891e68baaa9ef30abfe23d..be2d4970407c08afb1bf80d33f571f10fe736e9b 100644 (file)
 #ifndef        _D11_H
 #define        _D11_H
 
-#include <bcmdefs.h>
-#include <bcmdevs.h>
-#include <hndsoc.h>
-#include <sbhndpio.h>
-#include <sbhnddma.h>
-#include <proto/802.11.h>
-
 /* This marks the start of a packed structure section. */
 #include <packed_section_start.h>
 
diff --git a/drivers/staging/brcm80211/include/epivers.h b/drivers/staging/brcm80211/include/epivers.h
deleted file mode 100644 (file)
index 2e6b519..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _epivers_h_
-#define _epivers_h_
-
-#define        EPI_MAJOR_VERSION       5
-
-#define        EPI_MINOR_VERSION       75
-
-#define        EPI_RC_NUMBER           11
-
-#define        EPI_INCREMENTAL_NUMBER  0
-
-#define EPI_BUILD_NUMBER       1
-
-#define        EPI_VERSION             { 5, 75, 11, 0 }
-
-#ifdef BCMSDIO
-/* EPI_VERSION_NUM must match FW version */
-#define        EPI_VERSION_NUM         0x054b0c00
-#else
-#define        EPI_VERSION_NUM         0x054b0b00
-#endif
-
-#define EPI_VERSION_DEV                5.75.11
-
-/* Driver Version String, ASCII, 32 chars max */
-#define        EPI_VERSION_STR         "5.75.11"
-
-#endif                         /* _epivers_h_ */
index c9c860b6e474f87c9cdfa23dc6bab67c16e79685..586e652e75c725f5d6a1c1474c09640f89c3897e 100644 (file)
 #define _linux_osl_h_
 
 
-/* Linux Kernel: File Operations: start */
-extern void *osl_os_open_image(char *filename);
-extern int osl_os_get_image_block(char *buf, int len, void *image);
-extern void osl_os_close_image(void *image);
-/* Linux Kernel: File Operations: end */
-
-extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag);
+extern osl_t *osl_attach(void *pdev, uint bustype);
 extern void osl_detach(osl_t *osh);
 
 extern u32 g_assert_type;
@@ -62,7 +56,6 @@ extern uint osl_pci_slot(osl_t *osh);
 
 /* Pkttag flag should be part of public information */
 typedef struct {
-       bool pkttag;
        uint pktalloced;        /* Number of allocated packet buffers */
        bool mmbus;             /* Bus supports memory-mapped register accesses */
        pktfree_cb_fn_t tx_fn;  /* Callback function for PKTFREE */
@@ -91,8 +84,6 @@ typedef struct {
 
 #define BUS_SWAP32(v)          (v)
 
-#define        DMA_CONSISTENT_ALIGN    osl_dma_consistent_align()
-extern uint osl_dma_consistent_align(void);
 extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, u16 align,
                                      uint *tot, unsigned long *pap);
 
@@ -142,9 +133,6 @@ extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction);
 #define SELECT_BUS_READ(osh, mmap_op, bus_op) mmap_op
 #endif
 
-#define OSL_ERROR(bcmerror)    osl_error(bcmerror)
-extern int osl_error(int bcmerror);
-
 /* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */
 #define        PKTBUFSZ        2048    /* largest reasonable packet buffer, driver uses for ethernet MTU */
 
@@ -271,22 +259,6 @@ extern int osl_error(int bcmerror);
 #define OSL_CACHED(va)         ((void *)va)
 #endif                         /* mips */
 
-#if defined(mips)
-#define        OSL_GETCYCLES(x)        ((x) = read_c0_count() * 2)
-#elif defined(__i386__)
-#define        OSL_GETCYCLES(x)        rdtscl((x))
-#else
-#define OSL_GETCYCLES(x)       ((x) = 0)
-#endif                         /* defined(mips) */
-
-/* dereference an address that may cause a bus exception */
-#ifdef mips
-#define        BUSPROBE(val, addr)     get_dbe((val), (addr))
-#include <asm/paccess.h>
-#else
-#define        BUSPROBE(val, addr)     ({ (val) = R_REG(NULL, (addr)); 0; })
-#endif                         /* mips */
-
 /* map/unmap physical to virtual I/O */
 #if !defined(CONFIG_MMC_MSM7X00A)
 #define        REG_MAP(pa, size)       ioremap_nocache((unsigned long)(pa), (unsigned long)(size))
@@ -299,10 +271,6 @@ extern int osl_error(int bcmerror);
 #define        W_SM(r, v)              (*(r) = (v))
 #define        BZERO_SM(r, len)        memset((r), '\0', (len))
 
-#ifdef BRCM_FULLMAC
-#include <linuxver.h>          /* use current 2.4.x calling conventions */
-#endif
-
 /* packet primitives */
 #define        PKTGET(osh, len, send)          osl_pktget((osh), (len))
 #define        PKTFREE(osh, skb, send)         osl_pktfree((osh), (skb), (send))
@@ -316,7 +284,6 @@ extern int osl_error(int bcmerror);
 #define        PKTSETLEN(skb, len)     __skb_trim((struct sk_buff *)(skb), (len))
 #define        PKTPUSH(skb, bytes)     skb_push((struct sk_buff *)(skb), (bytes))
 #define        PKTPULL(skb, bytes)     skb_pull((struct sk_buff *)(skb), (bytes))
-#define        PKTTAG(skb)             ((void *)(((struct sk_buff *)(skb))->cb))
 #define PKTALLOCED(osh)                (((osl_pubinfo_t *)(osh))->pktalloced)
 #define PKTSETPOOL(osh, skb, x, y)     do {} while (0)
 #define PKTPOOL(osh, skb)              false
@@ -332,9 +299,6 @@ osl_pkt_frmnative(osl_pubinfo_t *osh, struct sk_buff *skb)
 {
        struct sk_buff *nskb;
 
-       if (osh->pkttag)
-               bzero((void *)skb->cb, OSL_PKTTAG_SZ);
-
        for (nskb = skb; nskb; nskb = nskb->next)
                osh->pktalloced++;
 
@@ -348,9 +312,6 @@ osl_pkt_tonative(osl_pubinfo_t *osh, void *pkt)
 {
        struct sk_buff *nskb;
 
-       if (osh->pkttag)
-               bzero(((struct sk_buff *)pkt)->cb, OSL_PKTTAG_SZ);
-
        for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next)
                osh->pktalloced--;
 
diff --git a/drivers/staging/brcm80211/include/linuxver.h b/drivers/staging/brcm80211/include/linuxver.h
deleted file mode 100644 (file)
index dc72141..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _linuxver_h_
-#define _linuxver_h_
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/workqueue.h>
-#include <linux/sched.h>
-#include <linux/ieee80211.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-
-#undef IP_TOS
-#include <asm/io.h>
-
-#endif                         /* _linuxver_h_ */
index c0ebb3d97220e6825c37a727a1d6099127a1c8de..bcb56aa5dc96689c6a8367ab4568fbc9ad487428 100644 (file)
@@ -21,8 +21,6 @@
 typedef struct osl_info osl_t;
 typedef struct osl_dmainfo osldma_t;
 
-#define OSL_PKTTAG_SZ  32      /* Size of PktTag */
-
 /* Drivers use PKTFREESETCB to register a callback function when a packet is freed by OSL */
 typedef void (*pktfree_cb_fn_t) (void *ctx, void *pkt, unsigned int status);
 
index 96866fb8898cef05988606931566e80bef51bbb9..45e02e5293ebfac38a88132c29ea2ca51e60fe18 100644 (file)
 #define BWL_DEFAULT_PACKING
 #include <packed_section_start.h>
 
-/* Legacy structure to help keep backward compatible wl tool and tray app */
-
-#define        LEGACY_WL_BSS_INFO_VERSION      107     /* older version of wl_bss_info struct */
-
-typedef struct wl_bss_info_107 {
-       u32 version;            /* version field */
-       u32 length;             /* byte length of data in this record,
-                                * starting at version and including IEs
-                                */
-       struct ether_addr BSSID;
-       u16 beacon_period;      /* units are Kusec */
-       u16 capability; /* Capability information */
-       u8 SSID_len;
-       u8 SSID[32];
-       struct {
-               uint count;     /* # rates in this set */
-               u8 rates[16];   /* rates in 500kbps units w/hi bit set if basic */
-       } rateset;              /* supported rates */
-       u8 channel;             /* Channel no. */
-       u16 atim_window;        /* units are Kusec */
-       u8 dtim_period; /* DTIM period */
-       s16 RSSI;               /* receive signal strength (in dBm) */
-       s8 phy_noise;           /* noise (in dBm) */
-       u32 ie_length;  /* byte length of Information Elements */
-       /* variable length Information Elements */
-} wl_bss_info_107_t;
-
-/*
- * Per-BSS information structure.
- */
-
-#define        LEGACY2_WL_BSS_INFO_VERSION     108     /* old version of wl_bss_info struct */
-
-/* BSS info structure
- * Applications MUST CHECK ie_offset field and length field to access IEs and
- * next bss_info structure in a vector (in wl_scan_results_t)
- */
-typedef struct wl_bss_info_108 {
-       u32 version;            /* version field */
-       u32 length;             /* byte length of data in this record,
-                                * starting at version and including IEs
-                                */
-       struct ether_addr BSSID;
-       u16 beacon_period;      /* units are Kusec */
-       u16 capability; /* Capability information */
-       u8 SSID_len;
-       u8 SSID[32];
-       struct {
-               uint count;     /* # rates in this set */
-               u8 rates[16];   /* rates in 500kbps units w/hi bit set if basic */
-       } rateset;              /* supported rates */
-       chanspec_t chanspec;    /* chanspec for bss */
-       u16 atim_window;        /* units are Kusec */
-       u8 dtim_period; /* DTIM period */
-       s16 RSSI;               /* receive signal strength (in dBm) */
-       s8 phy_noise;           /* noise (in dBm) */
-
-       u8 n_cap;               /* BSS is 802.11N Capable */
-       u32 nbss_cap;   /* 802.11N BSS Capabilities (based on HT_CAP_*) */
-       u8 ctl_ch;              /* 802.11N BSS control channel number */
-       u32 reserved32[1];      /* Reserved for expansion of BSS properties */
-       u8 flags;               /* flags */
-       u8 reserved[3]; /* Reserved for expansion of BSS properties */
-       u8 basic_mcs[MCSSET_LEN];       /* 802.11N BSS required MCS set */
-
-       u16 ie_offset;  /* offset at which IEs start, from beginning */
-       u32 ie_length;  /* byte length of Information Elements */
-       /* Add new fields here */
-       /* variable length Information Elements */
-} wl_bss_info_108_t;
-
 #ifdef BRCM_FULLMAC
+
 #define        WL_BSS_INFO_VERSION     108     /* current ver of wl_bss_info struct */
-#else
-#define        WL_BSS_INFO_VERSION     109     /* current ver of wl_bss_info struct */
-#endif
 
 /* BSS info structure
  * Applications MUST CHECK ie_offset field and length field to access IEs and
@@ -148,12 +75,14 @@ typedef struct wl_bss_info {
        /* Add new fields here */
        /* variable length Information Elements */
 } wl_bss_info_t;
+#endif /* BRCM_FULLMAC */
 
 typedef struct wlc_ssid {
        u32 SSID_len;
        unsigned char SSID[32];
 } wlc_ssid_t;
 
+#ifdef BRCM_FULLMAC
 typedef struct chan_scandata {
        u8 txpower;
        u8 pad;
@@ -308,6 +237,7 @@ typedef struct wl_probe_params {
        struct ether_addr bssid;
        struct ether_addr mac;
 } wl_probe_params_t;
+#endif /* BRCM_FULLMAC */
 
 #define WL_NUMRATES            16      /* max # of rates in a rateset */
 typedef struct wl_rateset {
@@ -315,6 +245,7 @@ typedef struct wl_rateset {
        u8 rates[WL_NUMRATES];  /* rates in 500kbps units w/hi bit set if basic */
 } wl_rateset_t;
 
+#ifdef BRCM_FULLMAC
 typedef struct wl_rateset_args {
        u32 count;              /* # rates in this set */
        u8 rates[WL_NUMRATES];  /* rates in 500kbps units w/hi bit set if basic */
@@ -352,6 +283,8 @@ typedef struct wl_join_params {
 } wl_join_params_t;
 #define WL_JOIN_PARAMS_FIXED_SIZE      (sizeof(wl_join_params_t) - sizeof(chanspec_t))
 
+#endif /* BRCM_FULLMAC */
+
 /* defines used by the nrate iovar */
 #define NRATE_MCS_INUSE        0x00000080      /* MSC in use,indicates b0-6 holds an mcs */
 #define NRATE_RATE_MASK 0x0000007f     /* rate/mcs value */
@@ -391,6 +324,7 @@ typedef struct {
 
 #define HIGHEST_SINGLE_STREAM_MCS      7       /* MCS values greater than this enable multiple streams */
 
+#ifdef BRCM_FULLMAC
 #define MAX_CCA_CHANNELS 38    /* Max number of 20 Mhz wide channels */
 #define MAX_CCA_SECS     60    /* CCA keeps this many seconds history */
 
@@ -428,8 +362,11 @@ typedef struct {
        cca_congest_t secs[1];  /* Data */
 } cca_congest_channel_req_t;
 
+#endif /* BRCM_FULLMAC */
+
 #define WLC_CNTRY_BUF_SZ       4       /* Country string is 3 bytes + NUL */
 
+#ifdef BRCM_FULLMAC
 typedef struct wl_country {
        char country_abbrev[WLC_CNTRY_BUF_SZ];  /* nul-terminated country code used in
                                                 * the Country IE
@@ -516,6 +453,7 @@ typedef struct wl_rm_rep {
        wl_rm_rep_elt_t rep[1]; /* variable length block of reports */
 } wl_rm_rep_t;
 #define WL_RM_REP_FIXED_LEN    8
+#endif /* BRCM_FULLMAC */
 
 /* Enumerate crypto algorithms */
 #define        CRYPTO_ALGO_OFF                 0
@@ -621,27 +559,6 @@ typedef struct wl_led_info {
        u8 activehi;
 } wl_led_info_t;
 
-/* flags */
-#define WLC_ASSOC_REQ_IS_REASSOC 0x01  /* assoc req was actually a reassoc */
-
-/* srom read/write struct passed through ioctl */
-typedef struct {
-       uint byteoff;           /* byte offset */
-       uint nbytes;            /* number of bytes */
-       u16 buf[1];
-} srom_rw_t;
-
-/* similar cis (srom or otp) struct [iovar: may not be aligned] */
-typedef struct {
-       u32 source;             /* cis source */
-       u32 byteoff;            /* byte offset */
-       u32 nbytes;             /* number of bytes */
-       /* data follows here */
-} cis_rw_t;
-
-#define WLC_CIS_DEFAULT        0       /* built-in default */
-#define WLC_CIS_SROM   1       /* source is sprom */
-#define WLC_CIS_OTP    2       /* source is otp */
 
 /* R_REG and W_REG struct passed through ioctl */
 typedef struct {
@@ -651,102 +568,14 @@ typedef struct {
        uint band;              /* band (optional) */
 } rw_reg_t;
 
-/* Structure used by GET/SET_ATTEN ioctls - it controls power in b/g-band */
-/* PCL - Power Control Loop */
-/* current gain setting is replaced by user input */
-#define WL_ATTEN_APP_INPUT_PCL_OFF     0       /* turn off PCL, apply supplied input */
-#define WL_ATTEN_PCL_ON                        1       /* turn on PCL */
-/* current gain setting is maintained */
-#define WL_ATTEN_PCL_OFF               2       /* turn off PCL. */
-
-typedef struct {
-       u16 auto_ctrl;  /* WL_ATTEN_XX */
-       u16 bb;         /* Baseband attenuation */
-       u16 radio;              /* Radio attenuation */
-       u16 txctl1;             /* Radio TX_CTL1 value */
-} atten_t;
-
-/* Per-AC retry parameters */
-struct wme_tx_params_s {
-       u8 short_retry;
-       u8 short_fallback;
-       u8 long_retry;
-       u8 long_fallback;
-       u16 max_rate;   /* In units of 512 Kbps */
-};
-
-typedef struct wme_tx_params_s wme_tx_params_t;
-
-#define WL_WME_TX_PARAMS_IO_BYTES (sizeof(wme_tx_params_t) * AC_COUNT)
-
-/* defines used by poweridx iovar - it controls power in a-band */
-/* current gain setting is maintained */
-#define WL_PWRIDX_PCL_OFF      -2      /* turn off PCL.  */
-#define WL_PWRIDX_PCL_ON       -1      /* turn on PCL */
-#define WL_PWRIDX_LOWER_LIMIT  -2      /* lower limit */
-#define WL_PWRIDX_UPPER_LIMIT  63      /* upper limit */
-/* value >= 0 causes
- *     - input to be set to that value
- *     - PCL to be off
- */
-
-/* Used to get specific link/ac parameters */
-typedef struct {
-       int ac;
-       u8 val;
-       struct ether_addr ea;
-} link_val_t;
-
-#define BCM_MAC_STATUS_INDICATION      (0x40010200L)
-
-typedef struct {
-       u16 ver;                /* version of this struct */
-       u16 len;                /* length in bytes of this structure */
-       u16 cap;                /* sta's advertised capabilities */
-       u32 flags;              /* flags defined below */
-       u32 idle;               /* time since data pkt rx'd from sta */
-       struct ether_addr ea;   /* Station address */
-       wl_rateset_t rateset;   /* rateset in use */
-       u32 in;         /* seconds elapsed since associated */
-       u32 listen_interval_inms;       /* Min Listen interval in ms for this STA */
-       u32 tx_pkts;            /* # of packets transmitted */
-       u32 tx_failures;        /* # of packets failed */
-       u32 rx_ucast_pkts;      /* # of unicast packets received */
-       u32 rx_mcast_pkts;      /* # of multicast packets received */
-       u32 tx_rate;            /* Rate of last successful tx frame */
-       u32 rx_rate;            /* Rate of last successful rx frame */
-       u32 rx_decrypt_succeeds;        /* # of packet decrypted successfully */
-       u32 rx_decrypt_failures;        /* # of packet decrypted unsuccessfully */
-} sta_info_t;
-
-#define WL_OLD_STAINFO_SIZE    offsetof(sta_info_t, tx_pkts)
-
-#define WL_STA_VER             3
-
-/* Flags for sta_info_t indicating properties of STA */
-#define WL_STA_BRCM            0x1     /* Running a Broadcom driver */
-#define WL_STA_WME             0x2     /* WMM association */
-#define WL_STA_ABCAP           0x4
-#define WL_STA_AUTHE           0x8     /* Authenticated */
-#define WL_STA_ASSOC           0x10    /* Associated */
-#define WL_STA_AUTHO           0x20    /* Authorized */
-#define WL_STA_WDS             0x40    /* Wireless Distribution System */
-#define WL_STA_WDS_LINKUP      0x80    /* WDS traffic/probes flowing properly */
-#define WL_STA_PS              0x100   /* STA is in power save mode from AP's viewpoint */
-#define WL_STA_APSD_BE         0x200   /* APSD delv/trigger for AC_BE is default enabled */
-#define WL_STA_APSD_BK         0x400   /* APSD delv/trigger for AC_BK is default enabled */
-#define WL_STA_APSD_VI         0x800   /* APSD delv/trigger for AC_VI is default enabled */
-#define WL_STA_APSD_VO         0x1000  /* APSD delv/trigger for AC_VO is default enabled */
-#define WL_STA_N_CAP           0x2000  /* STA 802.11n capable */
-#define WL_STA_SCBSTATS                0x4000  /* Per STA debug stats */
-
-#define WL_WDS_LINKUP          WL_STA_WDS_LINKUP       /* deprecated */
 
+#ifdef BRCM_FULLMAC
 /* Used to get specific STA parameters */
 typedef struct {
        u32 val;
        struct ether_addr ea;
 } scb_val_t;
+#endif /* BRCM_FULLMAC */
 
 /* channel encoding */
 typedef struct channel_info {
@@ -770,6 +599,7 @@ typedef struct get_pktcnt {
        uint rx_ocast_good_pkt; /* unicast packets destined for others */
 } get_pktcnt_t;
 
+#ifdef BRCM_FULLMAC
 /* Linux network driver ioctl encoding */
 typedef struct wl_ioctl {
        uint cmd;               /* common ioctl definition */
@@ -779,11 +609,8 @@ typedef struct wl_ioctl {
        uint used;              /* bytes read or written (optional) */
        uint needed;            /* bytes needed (optional) */
 } wl_ioctl_t;
+#endif /* BRCM_FULLMAC */
 
-/* reference to wl_ioctl_t struct used by usermode driver */
-#define ioctl_subtype  set     /* subtype param */
-#define ioctl_pid      used    /* pid param */
-#define ioctl_status   needed  /* status param */
 
 /*
  * Structure for passing hardware and software
@@ -810,45 +637,11 @@ typedef struct wlc_rev_info {
 
 #define WL_REV_INFO_LEGACY_LENGTH      48
 
-#define WL_BRAND_MAX 10
-typedef struct wl_instance_info {
-       uint instance;
-       char brand[WL_BRAND_MAX];
-} wl_instance_info_t;
-
-/* structure to change size of tx fifo */
-typedef struct wl_txfifo_sz {
-       u16 magic;
-       u16 fifo;
-       u16 size;
-} wl_txfifo_sz_t;
-/* magic pattern used for mismatch driver and wl */
-#define WL_TXFIFO_SZ_MAGIC     0xa5a5
-
-/* Transfer info about an IOVar from the driver */
-/* Max supported IOV name size in bytes, + 1 for nul termination */
-#define WLC_IOV_NAME_LEN 30
-typedef struct wlc_iov_trx_s {
-       u8 module;
-       u8 type;
-       char name[WLC_IOV_NAME_LEN];
-} wlc_iov_trx_t;
-
-/* check this magic number */
-#define WLC_IOCTL_MAGIC                0x14e46c77
-
-#define PROC_ENTRY_NAME "brcm_debug"
-/* bump this number if you change the ioctl interface */
-#define WLC_IOCTL_VERSION      1
-
 #ifdef BRCM_FULLMAC
-#define        WLC_IOCTL_MAXLEN        8192
-#else
-#define        WLC_IOCTL_MAXLEN                3072    /* max length ioctl buffer required */
-#endif
 #define        WLC_IOCTL_SMLEN                 256     /* "small" length ioctl buffer required */
 #define WLC_IOCTL_MEDLEN               1536    /* "med" length ioctl buffer required */
-#define WLC_SAMPLECOLLECT_MAXLEN       10240   /* Max Sample Collect buffer for two cores */
+#define        WLC_IOCTL_MAXLEN        8192
+#endif
 
 /* common ioctl definitions */
 #define WLC_GET_MAGIC                          0
@@ -1399,23 +1192,6 @@ typedef struct {
 #define WL_TX_POWER_MCS40_FIRST                28
 #define WL_TX_POWER_MCS40_NUM          17
 
-typedef struct {
-       u32 flags;
-       chanspec_t chanspec;    /* txpwr report for this channel */
-       chanspec_t local_chanspec;      /* channel on which we are associated */
-       u8 local_max;   /* local max according to the AP */
-       u8 local_constraint;    /* local constraint according to the AP */
-       s8 antgain[2];  /* Ant gain for each band - from SROM */
-       u8 rf_cores;            /* count of RF Cores being reported */
-       u8 est_Pout[4]; /* Latest tx power out estimate per RF
-                                * chain without adjustment
-                                */
-       u8 est_Pout_cck;        /* Latest CCK tx power out estimate */
-       u8 user_limit[WL_TX_POWER_RATES_LEGACY];        /* User limit */
-       u8 reg_limit[WL_TX_POWER_RATES_LEGACY]; /* Regulatory power limit */
-       u8 board_limit[WL_TX_POWER_RATES_LEGACY];       /* Max power board can support (SROM) */
-       u8 target[WL_TX_POWER_RATES_LEGACY];    /* Latest target power */
-} tx_power_legacy2_t;
 
 #define WL_TX_POWER_RATES             101
 #define WL_TX_POWER_CCK_FIRST         0
@@ -1848,63 +1624,6 @@ struct ampdu_retry_tid {
        u8 retry;               /* retry value */
 };
 
-/* structure for addts arguments */
-/* For ioctls that take a list of TSPEC */
-struct tslist {
-       int count;              /* number of tspecs */
-       struct tsinfo_arg tsinfo[1];    /* variable length array of tsinfo */
-};
-
-/* structure for addts/delts arguments */
-typedef struct tspec_arg {
-       u16 version;            /* see definition of TSPEC_ARG_VERSION */
-       u16 length;             /* length of entire structure */
-       uint flag;              /* bit field */
-       /* TSPEC Arguments */
-       struct tsinfo_arg tsinfo;       /* TS Info bit field */
-       u16 nom_msdu_size;      /* (Nominal or fixed) MSDU Size (bytes) */
-       u16 max_msdu_size;      /* Maximum MSDU Size (bytes) */
-       uint min_srv_interval;  /* Minimum Service Interval (us) */
-       uint max_srv_interval;  /* Maximum Service Interval (us) */
-       uint inactivity_interval;       /* Inactivity Interval (us) */
-       uint suspension_interval;       /* Suspension Interval (us) */
-       uint srv_start_time;    /* Service Start Time (us) */
-       uint min_data_rate;     /* Minimum Data Rate (bps) */
-       uint mean_data_rate;    /* Mean Data Rate (bps) */
-       uint peak_data_rate;    /* Peak Data Rate (bps) */
-       uint max_burst_size;    /* Maximum Burst Size (bytes) */
-       uint delay_bound;       /* Delay Bound (us) */
-       uint min_phy_rate;      /* Minimum PHY Rate (bps) */
-       u16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0 to 8.0) */
-       u16 medium_time;        /* Medium Time (32 us/s periods) */
-       u8 dialog_token;        /* dialog token */
-} tspec_arg_t;
-
-/* tspec arg for desired station */
-typedef struct tspec_per_sta_arg {
-       struct ether_addr ea;
-       struct tspec_arg ts;
-} tspec_per_sta_arg_t;
-
-/* structure for max bandwidth for each access category */
-typedef struct wme_max_bandwidth {
-       u32 ac[AC_COUNT];       /* max bandwidth for each access category */
-} wme_max_bandwidth_t;
-
-#define WL_WME_MBW_PARAMS_IO_BYTES (sizeof(wme_max_bandwidth_t))
-
-/* current version of wl_tspec_arg_t struct */
-#define        TSPEC_ARG_VERSION               2       /* current version of wl_tspec_arg_t struct */
-#define TSPEC_ARG_LENGTH               55      /* argument length from tsinfo to medium_time */
-#define TSPEC_DEFAULT_DIALOG_TOKEN     42      /* default dialog token */
-#define TSPEC_DEFAULT_SBW_FACTOR       0x3000  /* default surplus bw */
-
-/* define for flag */
-#define TSPEC_PENDING          0       /* TSPEC pending */
-#define TSPEC_ACCEPTED         1       /* TSPEC accepted */
-#define TSPEC_REJECTED         2       /* TSPEC rejected */
-#define TSPEC_UNKNOWN          3       /* TSPEC unknown */
-#define TSPEC_STATUS_MASK      7       /* TSPEC status mask */
 
 /* Software feature flag defines used by wlfeatureflag */
 #define WL_SWFL_NOHWRADIO      0x0004
@@ -1913,16 +1632,6 @@ typedef struct wme_max_bandwidth {
 
 #define WL_LIFETIME_MAX 0xFFFF /* Max value in ms */
 
-/*
- * Dongle pattern matching filter.
- */
-
-/* Packet filter types. Currently, only pattern matching is supported. */
-typedef enum wl_pkt_filter_type {
-       WL_PKT_FILTER_TYPE_PATTERN_MATCH        /* Pattern matching filter */
-} wl_pkt_filter_type_t;
-
-#define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t
 
 /* Pattern matching filter. Specifies an offset within received packets to
  * start matching, the pattern to match, the size of the pattern, and a bitmask
@@ -1957,20 +1666,6 @@ typedef struct wl_pkt_filter_enable {
        u32 enable;             /* Enable/disable bool */
 } wl_pkt_filter_enable_t;
 
-/* IOVAR "pkt_filter_list" parameter. Used to retrieve a list of installed filters. */
-typedef struct wl_pkt_filter_list {
-       u32 num;                /* Number of installed packet filters */
-       wl_pkt_filter_t filter[1];      /* Variable array of packet filters. */
-} wl_pkt_filter_list_t;
-
-#define WL_PKT_FILTER_LIST_FIXED_LEN     offsetof(wl_pkt_filter_list_t, filter)
-
-/* IOVAR "pkt_filter_stats" parameter. Used to retrieve debug statistics. */
-typedef struct wl_pkt_filter_stats {
-       u32 num_pkts_matched;   /* # filter matches for specified filter id */
-       u32 num_pkts_forwarded; /* # packets fwded from dongle to host for all filters */
-       u32 num_pkts_discarded; /* # packets discarded by dongle for all filters */
-} wl_pkt_filter_stats_t;
 
 #define        WLC_RSSI_INVALID         0      /* invalid RSSI value */
 
index 8287261120f4993eaaafe8c2c7d19e092e3f6006..9e6bbcdf8b6f2736eb49f08ecda19ecb3dbfce8a 100644 (file)
 #include <linux/string.h>
 #include <bcmdefs.h>
 #include <osl.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
 #include <bcmendian.h>
 #include <bcmnvram.h>
 #include <sbchipc.h>
+#include <bcmdevs.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
 
 #include <wlc_phy_int.h>
 #include <wlc_phyreg_n.h>
index 3d3112ed4e20499c9da964cf169ac80c1761205f..1fde9d5701b02c6bc93342eac517139328fc0bea 100644 (file)
 #include <wlc_cfg.h>
 #include <qmath.h>
 #include <osl.h>
-#include <linuxver.h>
+#include <linux/pci.h>
 #include <siutils.h>
 #include <hndpmu.h>
 
+#include <bcmdevs.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
+
 #include <wlc_phy_radio.h>
 #include <wlc_phy_int.h>
 #include <wlc_phy_lcn.h>
index 950008f122b1696b4a7e12567a22ff10b9557565..3e1ab579c0864badddcd0710c56953579c8932d7 100644 (file)
 #include <linux/string.h>
 #include <bcmdefs.h>
 #include <wlc_cfg.h>
-#include <linuxver.h>
+#include <linux/pci.h>
 #include <osl.h>
 #include <siutils.h>
 #include <sbchipc.h>
 #include <hndpmu.h>
 #include <bcmendian.h>
 
+#include <bcmdevs.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
+
 #include <wlc_phy_radio.h>
 #include <wlc_phy_int.h>
 #include <wlc_phyreg_n.h>
index 6ce9e5d96830b02e6dae52b7d6c19b2020c52ca4..330b88152b651023f9afb59dd1412ee887aff5d3 100644 (file)
@@ -15,6 +15,9 @@
  */
 
 #include <linux/types.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
+#include <osl.h>
 #include <wlc_phy_int.h>
 #include <wlc_phytbl_lcn.h>
 
index 7cc2c563c72730162e3b08cc192c91b14f7a22c8..a9fc193721ef548ac8d5c76c09b87b8d1312717f 100644 (file)
@@ -16,6 +16,9 @@
 
 #include <linux/kernel.h>
 
+#include <sbhndpio.h>
+#include <sbhnddma.h>
+#include <osl.h>
 #include <wlc_phy_int.h>
 #include <wlc_phytbl_n.h>
 
index d060377629ac2fc69320a17600a1371b201dec40..cb5dba95fc86bb1f191e2f55ebb3812e076e8403 100644 (file)
 #include <linux/string.h>
 #include <linux/pci_ids.h>
 #include <bcmdefs.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
 #include <osl.h>
 #define WLC_MAXBSSCFG          1       /* single BSS configs */
 
 #include <wlc_cfg.h>
 #include <net/mac80211.h>
-#include <epivers.h>
 #ifndef WLC_HIGH_ONLY
 #include <phy_version.h>
 #endif
@@ -35,6 +36,8 @@
 #include <pcicfg.h>
 #include <wlioctl.h>
 #include <wlc_key.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
 #include <wlc_channel.h>
 #include <wlc_pub.h>
 #include <wlc_scb.h>
@@ -786,8 +789,7 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs,
                return NULL;
        }
 
-       /* Requires pkttag feature */
-       osh = osl_attach(btparam, bustype, true);
+       osh = osl_attach(btparam, bustype);
        ASSERT(osh);
 
 #ifdef WLC_HIGH_ONLY
@@ -890,8 +892,8 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs,
        wl_release_fw(wl);
 #endif
        if (!wl->wlc) {
-               printf("%s: %s wlc_attach() failed with code %d\n",
-                       KBUILD_MODNAME, EPI_VERSION_STR, err);
+               printf("%s: wlc_attach() failed with code %d\n",
+                       KBUILD_MODNAME, err);
                goto fail;
        }
        wl->pub = wlc_pub(wl->wlc);
@@ -958,10 +960,10 @@ static wl_info_t *wl_attach(u16 vendor, u16 device, unsigned long regs,
        }
 #ifndef WLC_HIGH_ONLY
        WL_ERROR(("wl%d: Broadcom BCM43xx 802.11 MAC80211 Driver "
-                 EPI_VERSION_STR " (" PHY_VERSION_STR ")", unit));
+                 " (" PHY_VERSION_STR ")", unit));
 #else
-       WL_ERROR(("wl%d: Broadcom BCM43xx 802.11 MAC80211 Driver "
-                 EPI_VERSION_STR, unit));
+       WL_ERROR(("wl%d: Broadcom BCM43xx 802.11 Splitmac MAC80211 Driver "
+                 , unit));
 #endif
 
 #ifdef BCMDBG
index 2dc89f9c26352ef00d99fc33598c9dab79311772..8001dca44918f3c52b6f1f3892fc41b595b9f803 100644 (file)
 #include <linux/string.h>
 #include <bcmdefs.h>
 #include <wlc_cfg.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
 #include <osl.h>
 #include <bcmutils.h>
 #include <siutils.h>
 #include <wlioctl.h>
 #include <wlc_pub.h>
 #include <wlc_key.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
+#include <wlc_event.h>
 #include <wlc_mac80211.h>
 #include <wlc_alloc.h>
+#include <wl_dbg.h>
 
 static wlc_pub_t *wlc_pub_malloc(osl_t *osh, uint unit, uint *err,
                                 uint devid);
index a4e49f3c1363c6d95025e0c8fc4f3f7c1764b7a8..0bd7069dc331d0745a938f0b7afbadde6af6c6a5 100644 (file)
 #include <linux/kernel.h>
 #include <wlc_cfg.h>
 #include <bcmdefs.h>
-#include <linuxver.h>
-#include <bcmdefs.h>
 #include <osl.h>
 #include <bcmutils.h>
 #include <siutils.h>
 #include <bcmendian.h>
 #include <wlioctl.h>
+#include <sbhndpio.h>
 #include <sbhnddma.h>
 #include <hnddma.h>
 #include <d11.h>
 #include <wlc_rate.h>
 #include <wlc_pub.h>
 #include <wlc_key.h>
+#include <wlc_event.h>
 #include <wlc_mac80211.h>
 #include <wlc_phy_hal.h>
 #include <wlc_antsel.h>
@@ -36,6 +36,7 @@
 #include <net/mac80211.h>
 #include <wlc_ampdu.h>
 #include <wl_export.h>
+#include <wl_dbg.h>
 
 #ifdef WLC_HIGH_ONLY
 #include <bcm_rpc_tp.h>
index 5ff8831d2fa860f7b42e7240e8a6c9456514da30..ecc35de7700427121b19706d6f848c82fd9bf276 100644 (file)
 #ifdef WLANTSEL
 
 #include <linux/kernel.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
 #include <bcmdefs.h>
 #include <osl.h>
 #include <bcmutils.h>
 #include <siutils.h>
 #include <wlioctl.h>
 
+#include <bcmdevs.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
 #include <d11.h>
 #include <wlc_rate.h>
 #include <wlc_key.h>
 #include <wlc_pub.h>
 #include <wl_dbg.h>
+#include <wlc_event.h>
 #include <wlc_mac80211.h>
 #include <wlc_bmac.h>
 #include <wlc_phy_hal.h>
index b70f9d099233becbc9d3585df5589c33bfd1e5fd..fc5201d5171ada801d1b7bca1acb9e44d3994ed2 100644 (file)
@@ -20,7 +20,9 @@
 
 #include <linux/kernel.h>
 #include <wlc_cfg.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
 #include <bcmdefs.h>
 #include <osl.h>
 #include <proto/802.11.h>
 #include <wlc_channel.h>
 #include <bcmsrom.h>
 #include <wlc_key.h>
+#include <bcmdevs.h>
 /* BMAC_NOTE: a WLC_HIGH compile include of wlc.h adds in more structures and type
  * dependencies. Need to include these to files to allow a clean include of wlc.h
  * with WLC_HIGH defined.
  * At some point we may be able to skip the include of wlc.h and instead just
  * define a stub wlc_info and band struct to allow rpc calls to get the rpc handle.
  */
+#include <wlc_event.h>
 #include <wlc_mac80211.h>
 #include <wlc_bmac.h>
 #include <wlc_phy_shim.h>
@@ -69,6 +73,7 @@
 #include <pcie_core.h>
 
 #include <wlc_alloc.h>
+#include <wl_dbg.h>
 
 #define        TIMER_INTERVAL_WATCHDOG_BMAC    1000    /* watchdog timer, in unit of ms */
 
index 509280337e34ff15d1f8e2f5781be4831b5a7f78..2fcdbc72c837226269da12deaa45f7933dcb202d 100644 (file)
 #include <bcmdefs.h>
 #include <wlc_cfg.h>
 #include <osl.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
 #include <bcmutils.h>
 #include <siutils.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
 #include <wlioctl.h>
 #include <wlc_pub.h>
 #include <wlc_key.h>
+#include <wlc_event.h>
 #include <wlc_mac80211.h>
 #include <wlc_bmac.h>
 #include <wlc_stf.h>
 #include <wlc_channel.h>
+#include <wl_dbg.h>
 
 typedef struct wlc_cm_band {
        u8 locale_flags;        /* locale_info_t flags */
index 7e1bf0e2ecddbb87f26dd1c5b4eeca45f4c7f86a..e4ab077bf87f5c0d603bc8da0201fc3f56202264 100644 (file)
 
 #include <linux/kernel.h>
 #include <bcmdefs.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <osl.h>
 #include <bcmutils.h>
 #include <siutils.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
 #include <wlioctl.h>
 #include <wlc_cfg.h>
 #include <wlc_pub.h>
@@ -32,6 +36,7 @@
 #ifdef MSGTRACE
 #include <msgtrace.h>
 #endif
+#include <wl_dbg.h>
 
 /* Local prototypes */
 static void wlc_timer_cb(void *arg);
index feaffcc64ec6f7889168d2de1a811d867a2f91a8..a9fa48a14c5d7ebb7fa7c4e8bbd2e779ef4cd9dc 100644 (file)
@@ -16,8 +16,8 @@
 #include <linux/kernel.h>
 #include <linux/ctype.h>
 #include <bcmdefs.h>
+#include <bcmdevs.h>
 #include <wlc_cfg.h>
-#include <linuxver.h>
 #include <osl.h>
 #include <bcmutils.h>
 #include <bcmwifi.h>
@@ -27,7 +27,7 @@
 #include <pcicfg.h>
 #include <bcmsrom.h>
 #include <wlioctl.h>
-#include <epivers.h>
+#include <sbhndpio.h>
 #include <sbhnddma.h>
 #include <hnddma.h>
 #include <hndpmu.h>
@@ -37,6 +37,7 @@
 #include <wlc_key.h>
 #include <wlc_bsscfg.h>
 #include <wlc_channel.h>
+#include <wlc_event.h>
 #include <wlc_mac80211.h>
 #include <wlc_bmac.h>
 #include <wlc_scb.h>
@@ -61,6 +62,7 @@
 #endif                         /* WLC_HIGH_ONLY */
 #include <wlc_alloc.h>
 #include <net/mac80211.h>
+#include <wl_dbg.h>
 
 #ifdef WLC_HIGH_ONLY
 #undef R_REG
@@ -135,6 +137,8 @@ uint wl_msg_level =
 
 #define SCAN_IN_PROGRESS(x)    0
 
+#define EPI_VERSION_NUM                0x054b0b00
+
 #ifdef BCMDBG
 /* pointer to most recently allocated wl/wlc */
 static wlc_info_t *wlc_info_dbg = (wlc_info_t *) (NULL);
@@ -667,7 +671,7 @@ bool wlc_ps_check(wlc_info_t *wlc)
                 * may be either true or false due to the low level override.
                 */
                wake = STAY_AWAKE(wlc);
-               wake_ok = (wake && ((tmp & MCTL_WAKE) != 0)) || !wake;
+               wake_ok = ((tmp & MCTL_WAKE) != 0) || !wake;
 #endif
                if (hps && !wake_ok) {
                        WL_ERROR(("wl%d: wake not sync, sw %d maccontrol 0x%x\n", wlc->pub->unit, wake, tmp));
@@ -1780,8 +1784,10 @@ void *wlc_attach(void *wl, u16 vendor, u16 device, uint unit, bool piomode,
        ASSERT(sizeof(struct dot11_bcn_prb) == DOT11_BCN_PRB_LEN);
        ASSERT(sizeof(tx_status_t) == TXSTATUS_LEN);
        ASSERT(sizeof(ht_cap_ie_t) == HT_CAP_IE_LEN);
+#ifdef BRCM_FULLMAC
        ASSERT(offsetof(wl_scan_params_t, channel_list) ==
               WL_SCAN_PARAMS_FIXED_SIZE);
+#endif
        ASSERT(IS_ALIGNED(offsetof(wsec_key_t, data), sizeof(u32)));
        ASSERT(ISPOWEROF2(MA_WINDOW_SZ));
 
index 6a77591234b74f8b2aad944a4f9b864bfbf9f4ca..a3c6fb884990cd59c1022056ff7a8e6b423211f4 100644 (file)
 #ifndef _wlc_h_
 #define _wlc_h_
 
-#include <wlc_types.h>
-
-#include <wl_dbg.h>
 #include <wlioctl.h>
-#include <wlc_event.h>
 #include <wlc_phy_hal.h>
 #include <wlc_channel.h>
 #ifdef WLC_SPLIT
 #include <bcm_rpc.h>
 #endif
-
 #include <wlc_bsscfg.h>
-
 #include <wlc_scb.h>
 
 #define MA_WINDOW_SZ           8       /* moving average window size */
index bf8e2e1a15f64eeff973bc663caf3668186068ba..201ecdb319cd9c43250011a5876a10df31752ad0 100644 (file)
 #include <linux/kernel.h>
 #include <bcmdefs.h>
 #include <wlc_cfg.h>
-#include <linuxver.h>
-#include <bcmutils.h>
+#include <linux/module.h>
+#include <linux/pci.h>
 #include <osl.h>
+#include <bcmutils.h>
 
 #include <proto/802.11.h>
 #include <bcmwifi.h>
@@ -46,6 +47,7 @@
 #include <wlc_channel.h>
 #include <bcmsrom.h>
 #include <wlc_key.h>
+#include <wlc_event.h>
 
 #include <wlc_mac80211.h>
 
@@ -53,6 +55,7 @@
 #include <wlc_phy_shim.h>
 #include <wlc_phy_hal.h>
 #include <wl_export.h>
+#include <wl_dbg.h>
 
 /* PHY SHIM module specific state */
 struct wlc_phy_shim_info {
index a6a8c33483c92026f88401fdd0ef228654b346c2..f6ac5e99cf31c2f1f3b399c0a5a3807dea7dd590 100644 (file)
@@ -437,13 +437,9 @@ struct wlc_if;
 #define EDCF_ENAB(pub) (WME_ENAB(pub))
 #define QOS_ENAB(pub) (WME_ENAB(pub) || N_ENAB(pub))
 
-#define MONITOR_ENAB(wlc)      (bcmspace && (wlc)->monitor)
+#define MONITOR_ENAB(wlc)      ((wlc)->monitor)
 
-#define PROMISC_ENAB(wlc)      (bcmspace && (wlc)->promisc)
-
-extern void wlc_pkttag_info_move(wlc_pub_t *pub, void *pkt_from, void *pkt_to);
-
-#define WLPKTTAGSCB(p) (WLPKTTAG(p)->_scb)
+#define PROMISC_ENAB(wlc)      ((wlc)->promisc)
 
 #define        WLC_PREC_COUNT          16      /* Max precedence level implemented */
 
index d2d72568756dfdf3af8b64fb0ad3fd6c0ed93e2f..e1199b236f5fc577a7612548abde64c463da8cd6 100644 (file)
 #include <bcmdefs.h>
 #include <wlc_cfg.h>
 #include <osl.h>
-#include <linuxver.h>
+#include <linux/module.h>
 #include <bcmutils.h>
 #include <siutils.h>
 #include <bcmendian.h>
 #include <wlioctl.h>
 
+#include <sbhndpio.h>
+#include <sbhnddma.h>
 #include <proto/802.11.h>
 #include <d11.h>
 #include <wlc_rate.h>
index 4728ad90e295f8bb25adb721b92078f54ccde4f7..2bca0526b44c6a864667d6fe2aea2826014ae882 100644 (file)
@@ -15,8 +15,8 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <wlc_cfg.h>
-#include <linuxver.h>
 #include <bcmdefs.h>
 #include <osl.h>
 #include <bcmutils.h>
 #include <proto/802.11.h>
 #include <wlioctl.h>
 #include <bcmwifi.h>
+#include <sbhndpio.h>
+#include <sbhnddma.h>
 #include <d11.h>
 #include <wlc_rate.h>
 #include <wlc_pub.h>
 #include <wlc_key.h>
 #include <wlc_channel.h>
 #include <wlc_bsscfg.h>
+#include <wlc_event.h>
 #include <wlc_mac80211.h>
 #include <wlc_scb.h>
 #include <wl_export.h>
 #include <wlc_bmac.h>
 #include <wlc_stf.h>
+#include <wl_dbg.h>
 
 #define WLC_STF_SS_STBC_RX(wlc) (WLCISNPHY(wlc->band) && \
        NREV_GT(wlc->band->phyrev, 3) && NREV_LE(wlc->band->phyrev, 6))
index 75a7e3a5c0094023abf0eeea75e6a5ae40cfbaf2..1d4e3729ad618ce81998ccb6fa80d681a82ee7c8 100644 (file)
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <bcmdefs.h>
+#ifdef BRCM_FULLMAC
+#include <linux/netdevice.h>
+#endif
 #include <osl.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
 #include <bcmutils.h>
 #include <siutils.h>
 #include <hndsoc.h>
index c909832c7ee11848b1dd08075b3f7bf3644ff57f..9b1e6d961a726e553b3f44bd87b2292610f5952a 100644 (file)
@@ -18,7 +18,8 @@
 #include <linux/string.h>
 #include <bcmdefs.h>
 #include <osl.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
 #include <bcmdevs.h>
 #include <bcmutils.h>
 #include <siutils.h>
index 1282ef7eb922ed419948603878663f0743b1f943..4f3d3ca1af794e8e4d401a88b1f2235061c42c61 100644 (file)
@@ -17,7 +17,8 @@
 #include <linux/string.h>
 #include <bcmdefs.h>
 #include <osl.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
 #include <stdarg.h>
 #include <bcmutils.h>
 #include <hndsoc.h>
index 9789ea45ecd625c12ecec47f2900eed637201dbf..869d34c420d217b28e0616f4426fdff4be9300d4 100644 (file)
 #include <linux/string.h>
 #include <bcmdefs.h>
 #include <stdarg.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
 #include <osl.h>
-#include <linuxver.h>
 #include <bcmutils.h>
 #include <siutils.h>
 #include <bcmnvram.h>
@@ -30,7 +32,6 @@
 #include <proto/802.1d.h>
 #include <proto/802.11.h>
 
-
 /* copy a buffer into a pkt buffer chain */
 uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, unsigned char *buf)
 {
index 1bb6c78eece7dba9ee1f3e436990277312dc7c0d..81e54bd7a5542208a8c61856bdca6d4803846769 100644 (file)
  */
 #include <linux/ctype.h>
 #include <linux/kernel.h>
+#ifdef BRCM_FULLMAC
+#include <linux/netdevice.h>
+#endif
+#include <osl.h>
 #include <bcmdefs.h>
 #include <bcmutils.h>
 #include <bcmwifi.h>
index fe503e7de563889c6511a67e321859269904436b..b4dcb05705b3352c79c77d9defbbf54a828c31ff 100644 (file)
@@ -16,7 +16,8 @@
 
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linuxver.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
 #include <bcmdefs.h>
 #include <bcmdevs.h>
 #include <osl.h>
index a8f3306c1d2b447c87c33e85cbc19e33ea1ef5b2..6fb256bc5549c4786e42beb19a21f93b880cef62 100644 (file)
  */
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#ifdef BRCM_FULLMAC
+#include <linux/netdevice.h>
+#endif
 #include <bcmdefs.h>
 #include <osl.h>
 #include <bcmutils.h>
index 2bb5b8722df66ef485a136c0e5234f872669c5ec..7211f8a383ffd61acb085c181f7d9bb23d344d3d 100644 (file)
 #include <asm/paccess.h>
 #endif                         /* mips */
 #include <bcmendian.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/sched.h>
 #include <bcmdefs.h>
 #include <osl.h>
 #include <bcmutils.h>
@@ -36,82 +39,13 @@ struct osl_info {
        osl_pubinfo_t pub;
        uint magic;
        void *pdev;
-       uint failed;
        uint bustype;
 };
 
 /* Global ASSERT type flag */
 u32 g_assert_type;
 
-#ifdef BRCM_FULLMAC
-static s16 linuxbcmerrormap[] = { 0,   /* 0 */
-       -EINVAL,                /* BCME_ERROR */
-       -EINVAL,                /* BCME_BADARG */
-       -EINVAL,                /* BCME_BADOPTION */
-       -EINVAL,                /* BCME_NOTUP */
-       -EINVAL,                /* BCME_NOTDOWN */
-       -EINVAL,                /* BCME_NOTAP */
-       -EINVAL,                /* BCME_NOTSTA */
-       -EINVAL,                /* BCME_BADKEYIDX */
-       -EINVAL,                /* BCME_RADIOOFF */
-       -EINVAL,                /* BCME_NOTBANDLOCKED */
-       -EINVAL,                /* BCME_NOCLK */
-       -EINVAL,                /* BCME_BADRATESET */
-       -EINVAL,                /* BCME_BADBAND */
-       -E2BIG,                 /* BCME_BUFTOOSHORT */
-       -E2BIG,                 /* BCME_BUFTOOLONG */
-       -EBUSY,                 /* BCME_BUSY */
-       -EINVAL,                /* BCME_NOTASSOCIATED */
-       -EINVAL,                /* BCME_BADSSIDLEN */
-       -EINVAL,                /* BCME_OUTOFRANGECHAN */
-       -EINVAL,                /* BCME_BADCHAN */
-       -EFAULT,                /* BCME_BADADDR */
-       -ENOMEM,                /* BCME_NORESOURCE */
-       -EOPNOTSUPP,            /* BCME_UNSUPPORTED */
-       -EMSGSIZE,              /* BCME_BADLENGTH */
-       -EINVAL,                /* BCME_NOTREADY */
-       -EPERM,                 /* BCME_NOTPERMITTED */
-       -ENOMEM,                /* BCME_NOMEM */
-       -EINVAL,                /* BCME_ASSOCIATED */
-       -ERANGE,                /* BCME_RANGE */
-       -EINVAL,                /* BCME_NOTFOUND */
-       -EINVAL,                /* BCME_WME_NOT_ENABLED */
-       -EINVAL,                /* BCME_TSPEC_NOTFOUND */
-       -EINVAL,                /* BCME_ACM_NOTSUPPORTED */
-       -EINVAL,                /* BCME_NOT_WME_ASSOCIATION */
-       -EIO,                   /* BCME_SDIO_ERROR */
-       -ENODEV,                /* BCME_DONGLE_DOWN */
-       -EINVAL,                /* BCME_VERSION */
-       -EIO,                   /* BCME_TXFAIL */
-       -EIO,                   /* BCME_RXFAIL */
-       -EINVAL,                /* BCME_NODEVICE */
-       -EINVAL,                /* BCME_NMODE_DISABLED */
-       -ENODATA,               /* BCME_NONRESIDENT */
-
-/* When an new error code is added to bcmutils.h, add os
- * spcecific error translation here as well
- */
-/* check if BCME_LAST changed since the last time this function was updated */
-#if BCME_LAST != -42
-#error "You need to add a OS error translation in the linuxbcmerrormap \
-       for new error code defined in bcmutils.h"
-#endif
-};
-
-/* translate bcmerrors into linux errors */
-int osl_error(int bcmerror)
-{
-       if (bcmerror > 0)
-               bcmerror = 0;
-       else if (bcmerror < BCME_LAST)
-               bcmerror = BCME_ERROR;
-
-       /* Array bounds covered by ASSERT in osl_attach */
-       return linuxbcmerrormap[-bcmerror];
-}
-#endif /* BRCM_FULLMAC */
-
-osl_t *osl_attach(void *pdev, uint bustype, bool pkttag)
+osl_t *osl_attach(void *pdev, uint bustype)
 {
        osl_t *osh;
 
@@ -120,15 +54,8 @@ osl_t *osl_attach(void *pdev, uint bustype, bool pkttag)
 
        bzero(osh, sizeof(osl_t));
 
-#ifdef BRCM_FULLMAC
-       /* Check that error map has the right number of entries in it */
-       ASSERT(ABS(BCME_LAST) == (ARRAY_SIZE(linuxbcmerrormap) - 1));
-#endif /* BRCM_FULLMAC */
-
        osh->magic = OS_HANDLE_MAGIC;
-       osh->failed = 0;
        osh->pdev = pdev;
-       osh->pub.pkttag = pkttag;
        osh->bustype = bustype;
 
        switch (bustype) {
@@ -149,12 +76,6 @@ osl_t *osl_attach(void *pdev, uint bustype, bool pkttag)
                break;
        }
 
-#if defined(BCMDBG) && !defined(BRCM_FULLMAC)
-       if (pkttag) {
-               struct sk_buff *skb;
-               ASSERT(OSL_PKTTAG_SZ <= sizeof(skb->cb));
-       }
-#endif
        return osh;
 }
 
@@ -167,7 +88,6 @@ void osl_detach(osl_t *osh)
        kfree(osh);
 }
 
-/* Return a new packet. zero out pkttag */
 void *BCMFASTPATH osl_pktget(osl_t *osh, uint len)
 {
        struct sk_buff *skb;
@@ -282,11 +202,6 @@ uint osl_pci_slot(osl_t *osh)
        return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn);
 }
 
-uint osl_dma_consistent_align(void)
-{
-       return PAGE_SIZE;
-}
-
 void *osl_dma_alloc_consistent(osl_t *osh, uint size, u16 align_bits,
                               uint *alloced, unsigned long *pap)
 {
@@ -294,7 +209,7 @@ void *osl_dma_alloc_consistent(osl_t *osh, uint size, u16 align_bits,
 
        if (align_bits) {
                u16 align = (1 << align_bits);
-               if (!IS_ALIGNED(DMA_CONSISTENT_ALIGN, align))
+               if (!IS_ALIGNED(PAGE_SIZE, align))
                        size += align;
                *alloced = size;
        }
index 23f86dd7b1598bc5d9ae3591594f8a9e94241e0f..169a4287ee639c48adf9f4ec257ece33d8ea30d0 100644 (file)
@@ -15,7 +15,7 @@
  */
 
 #include <linux/string.h>
-#include <linuxver.h>
+#include <linux/pci.h>
 #include <bcmdefs.h>
 #include <osl.h>
 #include <bcmutils.h>
index e4c0baba553d82c362129ad37add164db6e43c38..82767e266e970d9e741d424a6c98a53e70d7ffb9 100644 (file)
@@ -16,6 +16,9 @@
 
 #include <linux/types.h>
 #include <bcmdefs.h>
+#ifdef BRCM_FULLMAC
+#include <linux/netdevice.h>
+#endif
 #include <osl.h>
 #include <bcmutils.h>
 #include <siutils.h>
index f3ea7e1a7aefd1367615c890ca4f4d86837bf3cc..3b99293307ea716f20fc34451592558d5a4eb5a2 100644 (file)
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <bcmdefs.h>
+#ifdef BRCM_FULLMAC
+#include <linux/netdevice.h>
+#endif
 #include <osl.h>
-#include <linuxver.h>
+#include <linux/module.h>
+#include <linux/pci.h>
 #include <bcmutils.h>
 #include <siutils.h>
 #include <bcmdevs.h>
index 93d7c056741d9367cb648302bf45da01711270d3..76f2483871a780b6b60140020d686d09218d1980 100644 (file)
@@ -2710,10 +2710,10 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
                        } else {
                                outl(0x83838383, devpriv->i_IobaseAmcc + 0x60);
                        }
-                       /*  Enable the interrupt for the controler */
+                       /*  Enable the interrupt for the controller */
                        dw_Dummy = inl(devpriv->i_IobaseAmcc + 0x38);
                        outl(dw_Dummy | 0x2000, devpriv->i_IobaseAmcc + 0x38);
-                       printk("\nEnable the interrupt for the controler");
+                       printk("\nEnable the interrupt for the controller");
                }
                printk("\nRead Eeprom");
                i_EepromReadMainHeader(io_addr[0], this_board->pc_EepromChip,
index 912bc0fc54bf3922574e6bbb8efb254aaaa5c7ef..a76ed2553fb427697eb127476a67bd93a14ab620 100644 (file)
@@ -225,7 +225,7 @@ int i_APCI1710_Reset(struct comedi_device *dev)
 
        devpriv->s_BoardInfos.b_BoardVersion = 1;
 
-       /*  Enable the interrupt for the controler */
+       /*  Enable the interrupt for the controller */
        dw_Dummy = inl(devpriv->s_BoardInfos.ui_Address + 0x38);
        outl(dw_Dummy | 0x2000, devpriv->s_BoardInfos.ui_Address + 0x38);
 
index b943a06e70dcd503b6ccaabeb30dffb3e965f957..a93e2349ad3a3b14ce426191733814add3c0aaf9 100644 (file)
@@ -3011,7 +3011,7 @@ int i_APCI3200_Reset(struct comedi_device *dev)
 
        outl(0x83838383, devpriv->i_IobaseAmcc + 0x60);
 
-       /*  Enable the interrupt for the controler */
+       /*  Enable the interrupt for the controller */
        dw_Dummy = inl(devpriv->i_IobaseAmcc + 0x38);
        outl(dw_Dummy | 0x2000, devpriv->i_IobaseAmcc + 0x38);
        outl(0, devpriv->i_IobaseAddon);        /* Resets the output */
index 60ebfc3c75fdb08aac1c22798d782d148006656d..aa8aeeee043fe7dabf9424fc60a1b62a87a2df7a 100644 (file)
@@ -753,7 +753,7 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it)
        struct comedi_subdevice *s;
        struct pci_dev *pcidev;
        int ret;
-       resource_size_t physLas0;       /* configuation */
+       resource_size_t physLas0;       /* configuration */
        resource_size_t physLas1;       /* data area */
        resource_size_t physLcfg;       /* PLX9080 */
 #ifdef USE_DMA
diff --git a/drivers/staging/cptm1217/Kconfig b/drivers/staging/cptm1217/Kconfig
new file mode 100644 (file)
index 0000000..f90545d
--- /dev/null
@@ -0,0 +1,11 @@
+config TOUCHSCREEN_CLEARPAD_TM1217
+       tristate "Synaptics Clearpad TM1217"
+       depends on I2C
+       depends on GPIOLIB
+       help
+         Say Y here if you have a Synaptics Clearpad TM1217 Controller
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called clearpad_tm1217.
diff --git a/drivers/staging/cptm1217/Makefile b/drivers/staging/cptm1217/Makefile
new file mode 100644 (file)
index 0000000..8961faf
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217)      += clearpad_tm1217.o
+
diff --git a/drivers/staging/cptm1217/TODO b/drivers/staging/cptm1217/TODO
new file mode 100644 (file)
index 0000000..3039224
--- /dev/null
@@ -0,0 +1,5 @@
+- Wait for the official upstream general clearpad drivers as promised over
+  the past few months
+- Merge any device support needed from this driver into it
+- Delete this driver
+
diff --git a/drivers/staging/cptm1217/clearpad_tm1217.c b/drivers/staging/cptm1217/clearpad_tm1217.c
new file mode 100644 (file)
index 0000000..269503f
--- /dev/null
@@ -0,0 +1,675 @@
+/*
+ * clearpad_tm1217.c - Touch Screen driver for Synaptics Clearpad
+ * TM1217 controller
+ *
+ * Copyright (C) 2008 Intel Corp
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; ifnot, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Questions/Comments/Bug fixes to Ramesh Agarwal (ramesh.agarwal@intel.com)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/timer.h>
+#include <linux/gpio.h>
+#include <linux/hrtimer.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include "cp_tm1217.h"
+
+#define CPTM1217_DEVICE_NAME           "cptm1217"
+#define CPTM1217_DRIVER_NAME           CPTM1217_DEVICE_NAME
+
+#define MAX_TOUCH_SUPPORTED            2
+#define TOUCH_SUPPORTED                        1
+#define SAMPLING_FREQ                  80      /* Frequency in HZ */
+#define DELAY_BTWIN_SAMPLE             (1000 / SAMPLING_FREQ)
+#define WAIT_FOR_RESPONSE              5       /* 5msec just works */
+#define MAX_RETRIES                    5       /* As above */
+#define INCREMENTAL_DELAY              5       /* As above */
+
+/* Regster Definitions */
+#define TMA1217_DEV_STATUS             0x13    /* Device Status */
+#define TMA1217_INT_STATUS             0x14    /* Interrupt Status */
+
+/* Controller can detect upto 2 possible finger touches.
+ * Each finger touch provides  12 bit X Y co-ordinates, the values are split
+ * across 2 registers, and an 8 bit  Z value */
+#define TMA1217_FINGER_STATE           0x18 /* Finger State */
+#define TMA1217_FINGER1_X_HIGHER8      0x19 /* Higher 8 bit of X coordinate */
+#define TMA1217_FINGER1_Y_HIGHER8      0x1A /* Higher 8 bit of Y coordinate */
+#define TMA1217_FINGER1_XY_LOWER4      0x1B /* Lower 4 bits of X and Y */
+#define TMA1217_FINGER1_Z_VALUE                0x1D /* 8 bit Z value for finger 1 */
+#define TMA1217_FINGER2_X_HIGHER8      0x1E /* Higher 8 bit of X coordinate */
+#define TMA1217_FINGER2_Y_HIGHER8      0x1F /* Higher 8 bit of Y coordinate */
+#define TMA1217_FINGER2_XY_LOWER4      0x20 /* Lower 4 bits of X and Y */
+#define TMA1217_FINGER2_Z_VALUE                0x22 /* 8 bit Z value for finger 2 */
+#define TMA1217_DEVICE_CTRL            0x23 /* Device Control */
+#define TMA1217_INTERRUPT_ENABLE       0x24 /* Interrupt Enable */
+#define TMA1217_REPORT_MODE            0x2B /* Reporting Mode */
+#define TMA1217_MAX_X_LOWER8           0x31 /* Bit 0-7 for Max X */
+#define TMA1217_MAX_X_HIGHER4          0x32 /* Bit 8-11 for Max X */
+#define TMA1217_MAX_Y_LOWER8           0x33 /* Bit 0-7 for Max Y */
+#define TMA1217_MAX_Y_HIGHER4          0x34 /* Bit 8-11 for Max Y */
+#define TMA1217_DEVICE_CMD_RESET       0x67 /* Device CMD reg for reset */
+#define TMA1217_DEVICE_CMD_REZERO      0x69 /* Device CMD reg for rezero */
+
+#define TMA1217_MANUFACTURER_ID                0x73 /* Manufacturer Id */
+#define TMA1217_PRODUCT_FAMILY         0x75 /* Product Family */
+#define TMA1217_FIRMWARE_REVISION      0x76 /* Firmware Revision */
+#define TMA1217_SERIAL_NO_HIGH         0x7C /* Bit 8-15 of device serial no. */
+#define TMA1217_SERIAL_NO_LOW          0x7D /* Bit 0-7 of device serial no. */
+#define TMA1217_PRODUCT_ID_START       0x7E /* Start address for 10 byte ID */
+#define TMA1217_DEVICE_CAPABILITY      0x8B /* Reporting capability */
+
+
+/*
+ * The touch position structure.
+ */
+struct touch_state {
+       int     x;
+       int     y;
+       bool button;
+};
+
+/* Device Specific info given by the controller */
+struct cp_dev_info {
+       u16     maxX;
+       u16     maxY;
+};
+
+/* Vendor related info given by the controller */
+struct cp_vendor_info {
+       u8      vendor_id;
+       u8      product_family;
+       u8      firmware_rev;
+       u16     serial_no;
+};
+
+/*
+ * Private structure to store the device details
+ */
+struct cp_tm1217_device {
+       struct i2c_client       *client;
+       struct device           *dev;
+       struct cp_vendor_info   vinfo;
+       struct cp_dev_info      dinfo;
+       struct input_dev_info {
+               char                    phys[32];
+               char                    name[128];
+               struct input_dev        *input;
+               struct touch_state      touch;
+       } cp_input_info[MAX_TOUCH_SUPPORTED];
+
+       int     thread_running;
+       struct mutex    thread_mutex;
+
+       int gpio;
+};
+
+
+/* The following functions are used to read/write registers on the device
+ * as per the RMI prorocol. Technically, a page select should be written
+ * before doing read/write but since the register offsets are below 0xFF
+ * we can use the default value of page which is 0x00
+ */
+static int cp_tm1217_read(struct cp_tm1217_device *ts,
+                               u8 *req, int size)
+{
+       int i, retval;
+
+       /* Send the address */
+       retval = i2c_master_send(ts->client, &req[0], 1);
+       if (retval != 1) {
+               dev_err(ts->dev, "cp_tm1217: I2C send failed\n");
+               return retval;
+       }
+       msleep(WAIT_FOR_RESPONSE);
+       for (i = 0; i < MAX_RETRIES; i++) {
+               retval = i2c_master_recv(ts->client, &req[1], size);
+               if (retval == size) {
+                       break;
+               } else {
+                       msleep(INCREMENTAL_DELAY);
+                       dev_dbg(ts->dev, "cp_tm1217: Retry count is %d\n", i);
+               }
+       }
+       if (retval != size)
+               dev_err(ts->dev, "cp_tm1217: Read from device failed\n");
+
+       return retval;
+}
+
+static int cp_tm1217_write(struct cp_tm1217_device *ts,
+                               u8 *req, int size)
+{
+       int retval;
+
+       /* Send the address and the data to be written */
+       retval = i2c_master_send(ts->client, &req[0], size + 1);
+       if (retval != size + 1) {
+               dev_err(ts->dev, "cp_tm1217: I2C write  failed: %d\n", retval);
+               return retval;
+       }
+       /* Wait for the write to complete. TBD why this is required */
+       msleep(WAIT_FOR_RESPONSE);
+
+       return size;
+}
+
+static int cp_tm1217_mask_interrupt(struct cp_tm1217_device *ts)
+{
+       u8 req[2];
+       int retval;
+
+       req[0] = TMA1217_INTERRUPT_ENABLE;
+       req[1] = 0x0;
+       retval = cp_tm1217_write(ts, req, 1);
+       if (retval != 1)
+               return -EIO;
+
+       return 0;
+}
+
+static int cp_tm1217_unmask_interrupt(struct cp_tm1217_device *ts)
+{
+       u8 req[2];
+       int retval;
+
+       req[0] = TMA1217_INTERRUPT_ENABLE;
+       req[1] = 0xa;
+       retval = cp_tm1217_write(ts, req, 1);
+       if (retval != 1)
+               return -EIO;
+
+       return 0;
+}
+
+static void process_touch(struct cp_tm1217_device *ts, int index)
+{
+       int retval;
+       struct input_dev_info *input_info =
+               (struct input_dev_info *)&ts->cp_input_info[index];
+       u8 xy_data[6];
+
+       if (index == 0)
+               xy_data[0] = TMA1217_FINGER1_X_HIGHER8;
+       else
+               xy_data[0] = TMA1217_FINGER2_X_HIGHER8;
+
+       retval = cp_tm1217_read(ts, xy_data, 5);
+       if (retval < 5) {
+               dev_err(ts->dev, "cp_tm1217: XY read from device failed\n");
+               return;
+       }
+
+       /* Note: Currently not using the Z values but may be requried in
+          the future. */
+       input_info->touch.x = (xy_data[1] << 4)
+                                       | (xy_data[3] & 0x0F);
+       input_info->touch.y = (xy_data[2] << 4)
+                                       | ((xy_data[3] & 0xF0) >> 4);
+       input_report_abs(input_info->input, ABS_X, input_info->touch.x);
+       input_report_abs(input_info->input, ABS_Y, input_info->touch.y);
+       input_sync(input_info->input);
+}
+
+static void cp_tm1217_get_data(struct cp_tm1217_device *ts)
+{
+       u8 req[2];
+       int retval, i, finger_touched = 0;
+
+       do {
+               req[0] = TMA1217_FINGER_STATE;
+               retval = cp_tm1217_read(ts, req, 1);
+               if (retval != 1) {
+                       dev_err(ts->dev,
+                               "cp_tm1217: Read from device failed\n");
+                       continue;
+               }
+               finger_touched = 0;
+               /* Start sampling until the pressure is below
+                 threshold */
+               for (i = 0; i < TOUCH_SUPPORTED; i++) {
+                       if (req[1] & 0x3) {
+                               finger_touched++;
+                               if (ts->cp_input_info[i].touch.button == 0) {
+                                       /* send the button touch event */
+                                       input_report_key(
+                                               ts->cp_input_info[i].input,
+                                               BTN_TOUCH, 1);
+                                       ts->cp_input_info[i].touch.button = 1;
+                               }
+                               process_touch(ts, i);
+                       } else {
+                               if (ts->cp_input_info[i].touch.button == 1) {
+                                       /* send the button release event */
+                                       input_report_key(
+                                               ts->cp_input_info[i].input,
+                                               BTN_TOUCH, 0);
+                                       input_sync(ts->cp_input_info[i].input);
+                                       ts->cp_input_info[i].touch.button = 0;
+                               }
+                       }
+                       req[1] = req[1] >> 2;
+               }
+               msleep(DELAY_BTWIN_SAMPLE);
+       } while (finger_touched > 0);
+}
+
+static irqreturn_t cp_tm1217_sample_thread(int irq, void *handle)
+{
+       struct cp_tm1217_device *ts = (struct cp_tm1217_device *) handle;
+       u8 req[2];
+       int retval;
+
+       /* Chedk if another thread is already running */
+       mutex_lock(&ts->thread_mutex);
+       if (ts->thread_running == 1) {
+               mutex_unlock(&ts->thread_mutex);
+               return IRQ_HANDLED;
+       } else {
+               ts->thread_running = 1;
+               mutex_unlock(&ts->thread_mutex);
+       }
+
+       /* Mask the interrupts */
+       retval = cp_tm1217_mask_interrupt(ts);
+
+       /* Read the Interrupt Status register to find the cause of the
+          Interrupt */
+       req[0] = TMA1217_INT_STATUS;
+       retval = cp_tm1217_read(ts, req, 1);
+       if (retval != 1)
+               goto exit_thread;
+
+       if (!(req[1] & 0x8))
+               goto exit_thread;
+
+       cp_tm1217_get_data(ts);
+
+exit_thread:
+       /* Unmask the interrupts before going to sleep */
+       retval = cp_tm1217_unmask_interrupt(ts);
+
+       mutex_lock(&ts->thread_mutex);
+       ts->thread_running = 0;
+       mutex_unlock(&ts->thread_mutex);
+
+       return IRQ_HANDLED;
+}
+
+static int cp_tm1217_init_data(struct cp_tm1217_device *ts)
+{
+       int retval;
+       u8      req[2];
+
+       /* Read the vendor id/ fw revision etc. Ignoring return check as this
+          is non critical info  */
+       req[0] = TMA1217_MANUFACTURER_ID;
+       retval = cp_tm1217_read(ts, req, 1);
+       ts->vinfo.vendor_id = req[1];
+
+       req[0] = TMA1217_PRODUCT_FAMILY;
+       retval = cp_tm1217_read(ts, req, 1);
+       ts->vinfo.product_family = req[1];
+
+       req[0] = TMA1217_FIRMWARE_REVISION;
+       retval = cp_tm1217_read(ts, req, 1);
+       ts->vinfo.firmware_rev = req[1];
+
+       req[0] = TMA1217_SERIAL_NO_HIGH;
+       retval = cp_tm1217_read(ts, req, 1);
+       ts->vinfo.serial_no = (req[1] << 8);
+
+       req[0] = TMA1217_SERIAL_NO_LOW;
+       retval = cp_tm1217_read(ts, req, 1);
+       ts->vinfo.serial_no = ts->vinfo.serial_no | req[1];
+
+       req[0] = TMA1217_MAX_X_HIGHER4;
+       retval = cp_tm1217_read(ts, req, 1);
+       ts->dinfo.maxX = (req[1] & 0xF) << 8;
+
+       req[0] = TMA1217_MAX_X_LOWER8;
+       retval = cp_tm1217_read(ts, req, 1);
+       ts->dinfo.maxX = ts->dinfo.maxX | req[1];
+
+       req[0] = TMA1217_MAX_Y_HIGHER4;
+       retval = cp_tm1217_read(ts, req, 1);
+       ts->dinfo.maxY = (req[1] & 0xF) << 8;
+
+       req[0] = TMA1217_MAX_Y_LOWER8;
+       retval = cp_tm1217_read(ts, req, 1);
+       ts->dinfo.maxY = ts->dinfo.maxY | req[1];
+
+       return 0;
+
+}
+
+/*
+ *     Set up a GPIO for use as the interrupt. We can't simply do this at
+ *     boot time because the GPIO drivers themselves may not be around at
+ *     boot/firmware set up time to do the work. Instead defer it to driver
+ *     detection.
+ */
+
+static int cp_tm1217_setup_gpio_irq(struct cp_tm1217_device *ts)
+{
+       int retval;
+
+       /* Hook up the irq handler */
+       retval = gpio_request(ts->gpio, "cp_tm1217_touch");
+       if (retval < 0) {
+               dev_err(ts->dev, "cp_tm1217: GPIO request failed error %d\n",
+                                                               retval);
+               return retval;
+       }
+
+       retval = gpio_direction_input(ts->gpio);
+       if (retval < 0) {
+               dev_err(ts->dev,
+               "cp_tm1217: GPIO direction configuration failed, error %d\n",
+                                                               retval);
+               gpio_free(ts->gpio);
+               return retval;
+       }
+
+       retval = gpio_to_irq(ts->gpio);
+       if (retval < 0) {
+               dev_err(ts->dev, "cp_tm1217: GPIO to IRQ failedi,"
+               " error %d\n", retval);
+               gpio_free(ts->gpio);
+       }
+       dev_dbg(ts->dev,
+               "cp_tm1217: Got IRQ number is %d for GPIO %d\n",
+               retval, ts->gpio);
+       return retval;
+}
+
+static int cp_tm1217_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct cp_tm1217_device *ts;
+       struct input_dev *input_dev;
+       struct input_dev_info   *input_info;
+       struct cp_tm1217_platform_data *pdata;
+       u8 req[2];
+       int i, retval;
+
+       /* No pdata is fine - we then use "normal" IRQ mode */
+
+       pdata = client->dev.platform_data;
+
+       ts = kzalloc(sizeof(struct cp_tm1217_device), GFP_KERNEL);
+       if (!ts) {
+               dev_err(&client->dev,
+                       "cp_tm1217: Private Device Struct alloc failed\n");
+               return -ENOMEM;
+       }
+
+       ts->client = client;
+       ts->dev = &client->dev;
+       i2c_set_clientdata(client, ts);
+
+       ts->thread_running = 0;
+       mutex_init(&ts->thread_mutex);
+
+       /* Reset the Controller */
+       req[0] = TMA1217_DEVICE_CMD_RESET;
+       req[1] = 0x1;
+       retval = cp_tm1217_write(ts, req, 1);
+       if (retval != 1) {
+               dev_err(ts->dev, "cp_tm1217: Controller reset failed\n");
+               kfree(ts);
+               return -EIO;
+       }
+
+       /* Clear up the interrupt status from reset. */
+       req[0] = TMA1217_INT_STATUS;
+       retval = cp_tm1217_read(ts, req, 1);
+
+       /* Mask all the interrupts */
+       retval = cp_tm1217_mask_interrupt(ts);
+
+       /* Read the controller information */
+       cp_tm1217_init_data(ts);
+
+       /* The following code will register multiple event devices when
+          multi-pointer is enabled, the code has not been tested
+          with MPX */
+       for (i = 0; i < TOUCH_SUPPORTED; i++) {
+               input_dev = input_allocate_device();
+               if (input_dev == NULL) {
+                       kfree(ts);
+                       dev_err(ts->dev,
+                               "cp_tm1217:Input Device Struct alloc failed\n");
+                       return -ENOMEM;
+               }
+               input_info = &ts->cp_input_info[i];
+               snprintf(input_info->name, sizeof(input_info->name),
+                       "cp_tm1217_touchscreen_%d", i);
+               input_dev->name = input_info->name;
+               snprintf(input_info->phys, sizeof(input_info->phys),
+                       "%s/input%d", dev_name(&client->dev), i);
+
+               input_dev->phys = input_info->phys;
+               input_dev->id.bustype = BUS_I2C;
+
+               input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+               input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+               input_set_abs_params(input_dev, ABS_X, 0, ts->dinfo.maxX, 0, 0);
+               input_set_abs_params(input_dev, ABS_Y, 0, ts->dinfo.maxY, 0, 0);
+
+               retval = input_register_device(input_dev);
+               if (retval) {
+                       dev_err(ts->dev,
+                               "Input dev registration failed for %s\n",
+                                       input_dev->name);
+                       goto fail;
+               }
+               input_info->input = input_dev;
+       }
+
+       /* Setup the reporting mode to send an interrupt only when
+          finger arrives or departs. */
+       req[0] = TMA1217_REPORT_MODE;
+       req[1] = 0x02;
+       retval = cp_tm1217_write(ts, req, 1);
+
+       /* Setup the device to no sleep mode for now and make it configured */
+       req[0] = TMA1217_DEVICE_CTRL;
+       req[1] = 0x84;
+       retval = cp_tm1217_write(ts, req, 1);
+
+       /* Check for the status of the device */
+       req[0] = TMA1217_DEV_STATUS;
+       retval = cp_tm1217_read(ts, req, 1);
+       if (req[1] != 0) {
+               dev_err(ts->dev,
+                       "cp_tm1217: Device Status 0x%x != 0: config failed\n",
+                       req[1]);
+
+               retval = -EIO;
+               goto fail;
+       }
+
+       if (pdata && pdata->gpio) {
+               ts->gpio = pdata->gpio;
+               retval = cp_tm1217_setup_gpio_irq(ts);
+       } else
+               retval = client->irq;
+
+       if (retval < 0) {
+               dev_err(ts->dev, "cp_tm1217: GPIO request failed error %d\n",
+                                                               retval);
+               goto fail;
+       }
+
+       client->irq = retval;
+
+
+       retval = request_threaded_irq(client->irq,
+               NULL, cp_tm1217_sample_thread,
+               IRQF_TRIGGER_FALLING, "cp_tm1217_touch", ts);
+       if (retval < 0) {
+               dev_err(ts->dev, "cp_tm1217: Request IRQ error %d\n", retval);
+               goto fail_gpio;
+       }
+
+       /* Unmask the interrupts */
+       retval = cp_tm1217_unmask_interrupt(ts);
+       if (retval == 0)
+               return 0;
+
+       free_irq(client->irq, ts);
+fail_gpio:
+       if (ts->gpio)
+               gpio_free(ts->gpio);
+fail:
+       /* Clean up before returning failure */
+       for (i = 0; i < TOUCH_SUPPORTED; i++) {
+               if (ts->cp_input_info[i].input) {
+                       input_unregister_device(ts->cp_input_info[i].input);
+                       input_free_device(ts->cp_input_info[i].input);
+               }
+       }
+       kfree(ts);
+       return retval;
+
+}
+
+/*
+ * cp_tm1217 suspend
+ *
+ */
+static int cp_tm1217_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+       struct cp_tm1217_device *ts = i2c_get_clientdata(client);
+       u8 req[2];
+       int retval;
+
+       /* Put the controller to sleep */
+       req[0] = TMA1217_DEVICE_CTRL;
+       retval = cp_tm1217_read(ts, req, 1);
+       req[1] = (req[1] & 0xF8) | 0x1;
+       retval = cp_tm1217_write(ts, req, 1);
+
+       if (device_may_wakeup(&client->dev))
+               enable_irq_wake(client->irq);
+
+       return 0;
+}
+
+/*
+ * cp_tm1217_resume
+ *
+ */
+static int cp_tm1217_resume(struct i2c_client *client)
+{
+       struct cp_tm1217_device *ts = i2c_get_clientdata(client);
+       u8 req[2];
+       int retval;
+
+       /* Take the controller out of sleep */
+       req[0] = TMA1217_DEVICE_CTRL;
+       retval = cp_tm1217_read(ts, req, 1);
+       req[1] = (req[1] & 0xF8) | 0x4;
+       retval = cp_tm1217_write(ts, req, 1);
+
+       /* Restore the register settings sinc the power to the
+          could have been cut off */
+
+       /* Setup the reporting mode to send an interrupt only when
+          finger arrives or departs. */
+       req[0] = TMA1217_REPORT_MODE;
+       req[1] = 0x02;
+       retval = cp_tm1217_write(ts, req, 1);
+
+       /* Setup the device to no sleep mode for now and make it configured */
+       req[0] = TMA1217_DEVICE_CTRL;
+       req[1] = 0x84;
+       retval = cp_tm1217_write(ts, req, 1);
+
+       /* Setup the interrupt mask */
+       retval = cp_tm1217_unmask_interrupt(ts);
+
+       if (device_may_wakeup(&client->dev))
+               disable_irq_wake(client->irq);
+
+       return 0;
+}
+
+/*
+ * cp_tm1217_remove
+ *
+ */
+static int cp_tm1217_remove(struct i2c_client *client)
+{
+       struct cp_tm1217_device *ts = i2c_get_clientdata(client);
+       int i;
+
+       free_irq(client->irq, ts);
+       if (ts->gpio)
+               gpio_free(ts->gpio);
+       for (i = 0; i < TOUCH_SUPPORTED; i++)
+               input_unregister_device(ts->cp_input_info[i].input);
+       kfree(ts);
+       return 0;
+}
+
+static struct i2c_device_id cp_tm1217_idtable[] = {
+       { CPTM1217_DEVICE_NAME, 0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, cp_tm1217_idtable);
+
+static struct i2c_driver cp_tm1217_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = CPTM1217_DRIVER_NAME,
+       },
+       .id_table       = cp_tm1217_idtable,
+       .probe          = cp_tm1217_probe,
+       .remove         = cp_tm1217_remove,
+       .suspend    = cp_tm1217_suspend,
+       .resume     = cp_tm1217_resume,
+};
+
+static int __init clearpad_tm1217_init(void)
+{
+       return i2c_add_driver(&cp_tm1217_driver);
+}
+
+static void __exit clearpad_tm1217_exit(void)
+{
+       i2c_del_driver(&cp_tm1217_driver);
+}
+
+module_init(clearpad_tm1217_init);
+module_exit(clearpad_tm1217_exit);
+
+MODULE_AUTHOR("Ramesh Agarwal <ramesh.agarwal@intel.com>");
+MODULE_DESCRIPTION("Synaptics TM1217 TouchScreen Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/cptm1217/cp_tm1217.h b/drivers/staging/cptm1217/cp_tm1217.h
new file mode 100644 (file)
index 0000000..a0ce31d
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __LINUX_I2C_CP_TM1217_H
+#define __LINUX_I2C_CP_TM1217_H
+
+struct cp_tm1217_platform_data
+{
+       int gpio;               /* If not set uses the IRQ resource 0 */
+};
+
+#endif
index ef7fbf8b069a58dea52e0374be2afcb575c79983..2babb034a25417286c008da4512099818c77ab36 100644 (file)
@@ -89,7 +89,7 @@ static int debug = ALPHATRACK_DEBUG;
 
 /* Use our own dbg macro */
 #define dbg_info(dev, format, arg...) do \
-    { if (debug) dev_info(dev , format , ## arg); } while (0)
+       { if (debug) dev_info(dev , format , ## arg); } while (0)
 
 #define alphatrack_ocmd_info(dev, cmd, format, arg...)
 
@@ -769,7 +769,7 @@ static int usb_alphatrack_probe(struct usb_interface *intf,
        }
 
        dev->write_buffer =
-           kmalloc(sizeof(struct alphatrack_ocmd) * true_size, GFP_KERNEL);
+           kmalloc(true_size * sizeof(struct alphatrack_ocmd), GFP_KERNEL);
 
        if (!dev->write_buffer) {
                dev_err(&intf->dev, "Couldn't allocate write_buffer\n");
index 87a6487531c2262e95357fac2987bc62a5d18e96..920ca52d6e4b5bd3a3525b06812359d843ebaaee 100644 (file)
@@ -64,7 +64,7 @@ spinlock_t free_buff_lock;
 int numofmsgbuf = 0;
 
 // Global variable to indicate that all provisioning data is sent to DSP
-//BOOLEAN fProvComplete;
+//bool fProvComplete;
 
 //
 // Table of entry-point routines for char device
@@ -623,10 +623,10 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
         memcpy(get_stat_data.eui64, info->eui64, EUISZ);
 
             if (info->ProgConStat != 0xFF) {
-                ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_LED, (PUCHAR)&ledStat, FT1000_MAG_DSP_LED_INDX);
+                ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_LED, (u8 *)&ledStat, FT1000_MAG_DSP_LED_INDX);
                 get_stat_data.LedStat = ntohs(ledStat);
                 DEBUG("FT1000:ft1000_ChIoctl: LedStat = 0x%x\n", get_stat_data.LedStat);
-                ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_CON_STATE, (PUCHAR)&conStat, FT1000_MAG_DSP_CON_STATE_INDX);
+                ft1000_read_dpram16(ft1000dev, FT1000_MAG_DSP_CON_STATE, (u8 *)&conStat, FT1000_MAG_DSP_CON_STATE_INDX);
                 get_stat_data.ConStat = ntohs(conStat);
                 DEBUG("FT1000:ft1000_ChIoctl: ConStat = 0x%x\n", get_stat_data.ConStat);
             }
@@ -653,12 +653,12 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
         {
             IOCTL_DPRAM_BLK *dpram_data;
             //IOCTL_DPRAM_COMMAND dpram_command;
-            USHORT qtype;
-            USHORT msgsz;
+            u16 qtype;
+            u16 msgsz;
                struct pseudo_hdr *ppseudo_hdr;
-            PUSHORT pmsg;
-            USHORT total_len;
-            USHORT app_index;
+            u16 *pmsg;
+            u16 total_len;
+            u16 app_index;
             u16 status;
 
             //DEBUG("FT1000:ft1000_ChIoctl: IOCTL_FT1000_SET_DPRAM called\n");
@@ -766,8 +766,8 @@ static long ft1000_ChIoctl (struct file *File, unsigned int Command,
                         // Make sure we are within the limits of the slow queue memory limitation
                         if ( (msgsz < MAX_CMD_SQSIZE) && (msgsz > PSEUDOSZ) ) {
                             // Need to put sequence number plus new checksum for message
-                            //pmsg = (PUSHORT)&dpram_command.dpram_blk.pseudohdr;
-                            pmsg = (PUSHORT)&dpram_data->pseudohdr;
+                            //pmsg = (u16 *)&dpram_command.dpram_blk.pseudohdr;
+                            pmsg = (u16 *)&dpram_data->pseudohdr;
                                ppseudo_hdr = (struct pseudo_hdr *)pmsg;
                             total_len = msgsz+2;
                             if (total_len & 0x1) {
index 4dd456fbab9b96233a3d8793a019386c4c08685a..e4905ad2badcebd1ad1bf7f56475399f7ec184cf 100644 (file)
@@ -123,11 +123,11 @@ struct dsp_image_info {
 // Notes:
 //
 //---------------------------------------------------------------------------
-static ULONG check_usb_db (struct ft1000_device *ft1000dev)
+static u32 check_usb_db (struct ft1000_device *ft1000dev)
 {
    int               loopcnt;
-   USHORT            temp;
-   ULONG             status;
+   u16            temp;
+   u32             status;
 
    loopcnt = 0;
    while (loopcnt < 10)
@@ -190,7 +190,7 @@ static ULONG check_usb_db (struct ft1000_device *ft1000dev)
 // Function:    get_handshake
 //
 // Parameters:  struct ft1000_device  - device structure
-//              USHORT expected_value - the handshake value expected
+//              u16 expected_value - the handshake value expected
 //
 // Returns:     handshakevalue - success
 //              HANDSHAKE_TIMEOUT_VALUE - failure
@@ -200,11 +200,11 @@ static ULONG check_usb_db (struct ft1000_device *ft1000dev)
 // Notes:
 //
 //---------------------------------------------------------------------------
-static USHORT get_handshake(struct ft1000_device *ft1000dev, USHORT expected_value)
+static u16 get_handshake(struct ft1000_device *ft1000dev, u16 expected_value)
 {
-   USHORT            handshake;
+   u16            handshake;
    int               loopcnt;
-   ULONG             status=0;
+   u32             status=0;
        struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net);
 
    loopcnt = 0;
@@ -228,7 +228,7 @@ static USHORT get_handshake(struct ft1000_device *ft1000dev, USHORT expected_val
                    status = ft1000_write_register (ft1000dev,  FT1000_DB_DNLD_RX, FT1000_REG_DOORBELL);
                }
 
-                status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (PUCHAR)&handshake, 1);
+                status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (u8 *)&handshake, 1);
                 //DEBUG("get_handshake: handshake is %x\n", tempx);
                 handshake = ntohs(handshake);
                 //DEBUG("get_handshake: after swap, handshake is %x\n", handshake);
@@ -259,7 +259,7 @@ static USHORT get_handshake(struct ft1000_device *ft1000dev, USHORT expected_val
 // Function:    put_handshake
 //
 // Parameters:  struct ft1000_device  - device structure
-//              USHORT handshake_value - handshake to be written
+//              u16 handshake_value - handshake to be written
 //
 // Returns:     none
 //
@@ -269,30 +269,30 @@ static USHORT get_handshake(struct ft1000_device *ft1000dev, USHORT expected_val
 // Notes:
 //
 //---------------------------------------------------------------------------
-static void put_handshake(struct ft1000_device *ft1000dev,USHORT handshake_value)
+static void put_handshake(struct ft1000_device *ft1000dev,u16 handshake_value)
 {
-    ULONG tempx;
-    USHORT tempword;
-    ULONG status;
+    u32 tempx;
+    u16 tempword;
+    u32 status;
 
 
 
-        tempx = (ULONG)handshake_value;
+        tempx = (u32)handshake_value;
         tempx = ntohl(tempx);
 
-        tempword = (USHORT)(tempx & 0xffff);
+        tempword = (u16)(tempx & 0xffff);
         status = ft1000_write_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, tempword, 0);
-        tempword = (USHORT)(tempx >> 16);
+        tempword = (u16)(tempx >> 16);
         status = ft1000_write_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, tempword, 1);
         status = ft1000_write_register(ft1000dev, FT1000_DB_DNLD_TX, FT1000_REG_DOORBELL);
 }
 
-static USHORT get_handshake_usb(struct ft1000_device *ft1000dev, USHORT expected_value)
+static u16 get_handshake_usb(struct ft1000_device *ft1000dev, u16 expected_value)
 {
-   USHORT            handshake;
+   u16            handshake;
    int               loopcnt;
-   USHORT            temp;
-   ULONG             status=0;
+   u16            temp;
+   u32             status=0;
 
        struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net);
    loopcnt = 0;
@@ -300,10 +300,10 @@ static USHORT get_handshake_usb(struct ft1000_device *ft1000dev, USHORT expected
    while (loopcnt < 100)
    {
        if (pft1000info->usbboot == 2) {
-           status = ft1000_read_dpram32 (ft1000dev, 0, (PUCHAR)&(pft1000info->tempbuf[0]), 64);
+           status = ft1000_read_dpram32 (ft1000dev, 0, (u8 *)&(pft1000info->tempbuf[0]), 64);
            for (temp=0; temp<16; temp++)
                DEBUG("tempbuf %d = 0x%x\n", temp, pft1000info->tempbuf[temp]);
-           status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (PUCHAR)&handshake, 1);
+           status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (u8 *)&handshake, 1);
            DEBUG("handshake from read_dpram16 = 0x%x\n", handshake);
            if (pft1000info->dspalive == pft1000info->tempbuf[6])
                handshake = 0;
@@ -313,7 +313,7 @@ static USHORT get_handshake_usb(struct ft1000_device *ft1000dev, USHORT expected
            }
        }
        else {
-           status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (PUCHAR)&handshake, 1);
+           status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_HANDSHAKE_LOC, (u8 *)&handshake, 1);
        }
        loopcnt++;
        msleep(10);
@@ -327,7 +327,7 @@ static USHORT get_handshake_usb(struct ft1000_device *ft1000dev, USHORT expected
    return HANDSHAKE_TIMEOUT_VALUE;
 }
 
-static void put_handshake_usb(struct ft1000_device *ft1000dev,USHORT handshake_value)
+static void put_handshake_usb(struct ft1000_device *ft1000dev,u16 handshake_value)
 {
    int i;
 
@@ -346,44 +346,44 @@ static void put_handshake_usb(struct ft1000_device *ft1000dev,USHORT handshake_v
 // Notes:
 //
 //---------------------------------------------------------------------------
-static USHORT get_request_type(struct ft1000_device *ft1000dev)
+static u16 get_request_type(struct ft1000_device *ft1000dev)
 {
-   USHORT   request_type;
-   ULONG    status;
-   USHORT   tempword;
-   ULONG    tempx;
+   u16   request_type;
+   u32    status;
+   u16   tempword;
+   u32    tempx;
        struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net);
 
    if ( pft1000info->bootmode == 1)
    {
-       status = fix_ft1000_read_dpram32 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempx);
+       status = fix_ft1000_read_dpram32 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (u8 *)&tempx);
        tempx = ntohl(tempx);
    }
    else
    {
        tempx = 0;
 
-       status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempword, 1);
+       status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (u8 *)&tempword, 1);
        tempx |= (tempword << 16);
        tempx = ntohl(tempx);
    }
-   request_type = (USHORT)tempx;
+   request_type = (u16)tempx;
 
    //DEBUG("get_request_type: request_type is %x\n", request_type);
    return request_type;
 
 }
 
-static USHORT get_request_type_usb(struct ft1000_device *ft1000dev)
+static u16 get_request_type_usb(struct ft1000_device *ft1000dev)
 {
-   USHORT   request_type;
-   ULONG    status;
-   USHORT   tempword;
-   ULONG    tempx;
+   u16   request_type;
+   u32    status;
+   u16   tempword;
+   u32    tempx;
        struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net);
    if ( pft1000info->bootmode == 1)
    {
-       status = fix_ft1000_read_dpram32 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempx);
+       status = fix_ft1000_read_dpram32 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (u8 *)&tempx);
        tempx = ntohl(tempx);
    }
    else
@@ -394,12 +394,12 @@ static USHORT get_request_type_usb(struct ft1000_device *ft1000dev)
        }
        else {
           tempx = 0;
-          status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (PUCHAR)&tempword, 1);
+          status = ft1000_read_dpram16 (ft1000dev, DWNLD_MAG1_TYPE_LOC, (u8 *)&tempword, 1);
        }
        tempx |= (tempword << 16);
        tempx = ntohl(tempx);
    }
-   request_type = (USHORT)tempx;
+   request_type = (u16)tempx;
 
    //DEBUG("get_request_type: request_type is %x\n", request_type);
    return request_type;
@@ -420,22 +420,22 @@ static USHORT get_request_type_usb(struct ft1000_device *ft1000dev)
 //---------------------------------------------------------------------------
 static long get_request_value(struct ft1000_device *ft1000dev)
 {
-   ULONG     value;
-   USHORT   tempword;
-   ULONG    status;
+   u32     value;
+   u16   tempword;
+   u32    status;
        struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net);
 
 
        if ( pft1000info->bootmode == 1)
        {
-          status = fix_ft1000_read_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&value);
+          status = fix_ft1000_read_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, (u8 *)&value);
           value = ntohl(value);
        }
        else
        {
-          status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempword, 0);
+          status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 0);
           value = tempword;
-           status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempword, 1);
+           status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 1);
           value |= (tempword << 16);
           value = ntohl(value);
        }
@@ -449,9 +449,9 @@ static long get_request_value(struct ft1000_device *ft1000dev)
 #if 0
 static long get_request_value_usb(struct ft1000_device *ft1000dev)
 {
-   ULONG     value;
-   USHORT   tempword;
-   ULONG    status;
+   u32     value;
+   u16   tempword;
+   u32    status;
    struct ft1000_info * pft1000info = netdev_priv(ft1000dev->net);
 
        if (pft1000info->usbboot == 2) {
@@ -460,7 +460,7 @@ static long get_request_value_usb(struct ft1000_device *ft1000dev)
        }
        else {
           value = 0;
-          status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempword, 1);
+          status = ft1000_read_dpram16(ft1000dev, DWNLD_MAG1_SIZE_LOC, (u8 *)&tempword, 1);
        }
 
        value |= (tempword << 16);
@@ -490,11 +490,11 @@ static long get_request_value_usb(struct ft1000_device *ft1000dev)
 //---------------------------------------------------------------------------
 static void put_request_value(struct ft1000_device *ft1000dev, long lvalue)
 {
-   ULONG    tempx;
-   ULONG    status;
+   u32    tempx;
+   u32    status;
 
        tempx = ntohl(lvalue);
-       status = fix_ft1000_write_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, (PUCHAR)&tempx);
+       status = fix_ft1000_write_dpram32(ft1000dev, DWNLD_MAG1_SIZE_LOC, (u8 *)&tempx);
 
 
 
@@ -516,10 +516,10 @@ static void put_request_value(struct ft1000_device *ft1000dev, long lvalue)
 // Notes:
 //
 //---------------------------------------------------------------------------
-static USHORT hdr_checksum(struct pseudo_hdr *pHdr)
+static u16 hdr_checksum(struct pseudo_hdr *pHdr)
 {
-   USHORT   *usPtr = (USHORT *)pHdr;
-   USHORT   chksum;
+   u16   *usPtr = (u16 *)pHdr;
+   u16   chksum;
 
 
   chksum = ((((((usPtr[0] ^ usPtr[1]) ^ usPtr[2]) ^ usPtr[3]) ^
@@ -533,8 +533,8 @@ static USHORT hdr_checksum(struct pseudo_hdr *pHdr)
 // Function:    write_blk
 //
 // Parameters:  struct ft1000_device  - device structure
-//              USHORT **pUsFile - DSP image file pointer in USHORT
-//              UCHAR  **pUcFile - DSP image file pointer in UCHAR
+//              u16 **pUsFile - DSP image file pointer in u16
+//              u8  **pUcFile - DSP image file pointer in u8
 //              long   word_length - lenght of the buffer to be written
 //                                   to DPRAM
 //
@@ -546,20 +546,20 @@ static USHORT hdr_checksum(struct pseudo_hdr *pHdr)
 // Notes:
 //
 //---------------------------------------------------------------------------
-static ULONG write_blk (struct ft1000_device *ft1000dev, USHORT **pUsFile, UCHAR **pUcFile, long word_length)
+static u32 write_blk (struct ft1000_device *ft1000dev, u16 **pUsFile, u8 **pUcFile, long word_length)
 {
-   ULONG Status = STATUS_SUCCESS;
-   USHORT dpram;
+   u32 Status = STATUS_SUCCESS;
+   u16 dpram;
    long temp_word_length;
    int loopcnt, i, j;
-   USHORT *pTempFile;
-   USHORT tempword;
-   USHORT tempbuffer[64];
-   USHORT resultbuffer[64];
+   u16 *pTempFile;
+   u16 tempword;
+   u16 tempbuffer[64];
+   u16 resultbuffer[64];
        struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net);
 
    //DEBUG("FT1000:download:start word_length = %d\n",(int)word_length);
-   dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC;
+   dpram = (u16)DWNLD_MAG1_PS_HDR_LOC;
    tempword = *(*pUsFile);
    (*pUsFile)++;
    Status = ft1000_write_dpram16(ft1000dev, dpram, tempword, 0);
@@ -569,7 +569,7 @@ static ULONG write_blk (struct ft1000_device *ft1000dev, USHORT **pUsFile, UCHAR
 
    *pUcFile = *pUcFile + 4;
    word_length--;
-   tempword = (USHORT)word_length;
+   tempword = (u16)word_length;
    word_length = (word_length / 16) + 1;
    pTempFile = *pUsFile;
    temp_word_length = word_length;
@@ -602,24 +602,24 @@ static ULONG write_blk (struct ft1000_device *ft1000dev, USHORT **pUsFile, UCHAR
              if (pft1000info->bootmode == 0)
              {
                 if (dpram >= 0x3F4)
-                     Status = ft1000_write_dpram32 (ft1000dev, dpram, (PUCHAR)&tempbuffer[0], 8);
+                     Status = ft1000_write_dpram32 (ft1000dev, dpram, (u8 *)&tempbuffer[0], 8);
                 else
-                    Status = ft1000_write_dpram32 (ft1000dev, dpram, (PUCHAR)&tempbuffer[0], 64);
+                    Status = ft1000_write_dpram32 (ft1000dev, dpram, (u8 *)&tempbuffer[0], 64);
              }
              else
              {
                  for (j=0; j<10; j++)
                  {
-                   Status = ft1000_write_dpram32 (ft1000dev, dpram, (PUCHAR)&tempbuffer[0], 64);
+                   Status = ft1000_write_dpram32 (ft1000dev, dpram, (u8 *)&tempbuffer[0], 64);
                   if (Status == STATUS_SUCCESS)
                   {
                       // Work around for ASIC bit stuffing problem.
                       if ( (tempbuffer[31] & 0xfe00) == 0xfe00)
                       {
-                          Status = ft1000_write_dpram32(ft1000dev, dpram+12, (PUCHAR)&tempbuffer[24], 64);
+                          Status = ft1000_write_dpram32(ft1000dev, dpram+12, (u8 *)&tempbuffer[24], 64);
                       }
                       // Let's check the data written
-                      Status = ft1000_read_dpram32 (ft1000dev, dpram, (PUCHAR)&resultbuffer[0], 64);
+                      Status = ft1000_read_dpram32 (ft1000dev, dpram, (u8 *)&resultbuffer[0], 64);
                       if ( (tempbuffer[31] & 0xfe00) == 0xfe00)
                       {
                           for (i=0; i<28; i++)
@@ -633,7 +633,7 @@ static ULONG write_blk (struct ft1000_device *ft1000dev, USHORT **pUsFile, UCHAR
                                   break;
                                }
                           }
-                          Status = ft1000_read_dpram32 (ft1000dev, dpram+12, (PUCHAR)&resultbuffer[0], 64);
+                          Status = ft1000_read_dpram32 (ft1000dev, dpram+12, (u8 *)&resultbuffer[0], 64);
                           for (i=0; i<16; i++)
                           {
                               if (resultbuffer[i] != tempbuffer[i+24])
@@ -689,8 +689,8 @@ static void usb_dnld_complete (struct urb *urb)
 // Function:    write_blk_fifo
 //
 // Parameters:  struct ft1000_device  - device structure
-//              USHORT **pUsFile - DSP image file pointer in USHORT
-//              UCHAR  **pUcFile - DSP image file pointer in UCHAR
+//              u16 **pUsFile - DSP image file pointer in u16
+//              u8  **pUcFile - DSP image file pointer in u8
 //              long   word_length - lenght of the buffer to be written
 //                                   to DPRAM
 //
@@ -702,9 +702,9 @@ static void usb_dnld_complete (struct urb *urb)
 // Notes:
 //
 //---------------------------------------------------------------------------
-static ULONG write_blk_fifo (struct ft1000_device *ft1000dev, USHORT **pUsFile, UCHAR **pUcFile, long word_length)
+static u32 write_blk_fifo (struct ft1000_device *ft1000dev, u16 **pUsFile, u8 **pUcFile, long word_length)
 {
-   ULONG Status = STATUS_SUCCESS;
+   u32 Status = STATUS_SUCCESS;
    int byte_length;
    long aligncnt;
 
@@ -770,36 +770,36 @@ static ULONG write_blk_fifo (struct ft1000_device *ft1000dev, USHORT **pUsFile,
 //  Returns:    status                  - return code
 //---------------------------------------------------------------------------
 
-u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG  FileLength)
+u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32  FileLength)
 {
    u16                     Status = STATUS_SUCCESS;
-   UINT                    uiState;
-   USHORT                  handshake;
+   u32                    uiState;
+   u16                  handshake;
        struct pseudo_hdr *pHdr;
-   USHORT                  usHdrLength;
+   u16                  usHdrLength;
    long                    word_length;
-   USHORT                  request;
-   USHORT                  temp;
-   USHORT                  tempword;
+   u16                  request;
+   u16                  temp;
+   u16                  tempword;
 
        struct dsp_file_hdr *pFileHdr5;
        struct dsp_image_info *pDspImageInfoV6 = NULL;
    long                    requested_version;
-   BOOLEAN                 bGoodVersion;
+   bool                 bGoodVersion;
        struct drv_msg *pMailBoxData;
-   USHORT                  *pUsData = NULL;
-   USHORT                  *pUsFile = NULL;
-   UCHAR                   *pUcFile = NULL;
-   UCHAR                   *pBootEnd = NULL, *pCodeEnd= NULL;
+   u16                  *pUsData = NULL;
+   u16                  *pUsFile = NULL;
+   u8                   *pUcFile = NULL;
+   u8                   *pBootEnd = NULL, *pCodeEnd= NULL;
    int                     imageN;
    long                    loader_code_address, loader_code_size = 0;
    long                    run_address = 0, run_size = 0;
 
-   ULONG                   templong;
-   ULONG                   image_chksum = 0;
+   u32                   templong;
+   u32                   image_chksum = 0;
 
-   USHORT                  dpram = 0;
-   PUCHAR                  pbuffer;
+   u16                  dpram = 0;
+   u8 *pbuffer;
        struct prov_record *pprov_record;
        struct ft1000_info *pft1000info = netdev_priv(ft1000dev->net);
 
@@ -820,10 +820,10 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG  FileLe
 
    ft1000_write_register (ft1000dev, 0x800, FT1000_REG_MAG_WATERMARK);
 
-      pUsFile = (USHORT *)(pFileStart + pFileHdr5->loader_offset);
-      pUcFile = (UCHAR *)(pFileStart + pFileHdr5->loader_offset);
+      pUsFile = (u16 *)(pFileStart + pFileHdr5->loader_offset);
+      pUcFile = (u8 *)(pFileStart + pFileHdr5->loader_offset);
 
-      pBootEnd = (UCHAR *)(pFileStart + pFileHdr5->loader_code_end);
+      pBootEnd = (u8 *)(pFileStart + pFileHdr5->loader_code_end);
 
       loader_code_address = pFileHdr5->loader_code_address;
       loader_code_size = pFileHdr5->loader_code_size;
@@ -878,8 +878,8 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG  FileLe
             case  REQUEST_DONE_BL:
                DEBUG("FT1000:REQUEST_DONE_BL\n");
                /* Reposition ptrs to beginning of code section */
-               pUsFile = (USHORT *)(pBootEnd);
-               pUcFile = (UCHAR *)(pBootEnd);
+               pUsFile = (u16 *)(pBootEnd);
+               pUcFile = (u8 *)(pBootEnd);
                //DEBUG("FT1000:download:pUsFile = 0x%8x\n", (int)pUsFile);
                //DEBUG("FT1000:download:pUcFile = 0x%8x\n", (int)pUcFile);
                uiState = STATE_CODE_DWNLD;
@@ -909,7 +909,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG  FileLe
                /*
                 * Position ASIC DPRAM auto-increment pointer.
                 */
-                                   dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC;
+                                   dpram = (u16)DWNLD_MAG1_PS_HDR_LOC;
                                        if (word_length & 0x1)
                                                word_length++;
                                        word_length = word_length / 2;
@@ -988,8 +988,8 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG  FileLe
             case  REQUEST_DONE_CL:
                pft1000info->usbboot = 3;
                /* Reposition ptrs to beginning of provisioning section */
-                  pUsFile = (USHORT *)(pFileStart + pFileHdr5->commands_offset);
-                  pUcFile = (UCHAR *)(pFileStart + pFileHdr5->commands_offset);
+                  pUsFile = (u16 *)(pFileStart + pFileHdr5->commands_offset);
+                  pUcFile = (u8 *)(pFileStart + pFileHdr5->commands_offset);
                uiState = STATE_DONE_DWNLD;
                break;
             case  REQUEST_CODE_SEGMENT:
@@ -1027,7 +1027,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG  FileLe
                /*
                 * Position ASIC DPRAM auto-increment pointer.
                 */
-                  dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC;
+                  dpram = (u16)DWNLD_MAG1_PS_HDR_LOC;
                   if (word_length & 0x1)
                        word_length++;
                   word_length = word_length / 2;
@@ -1053,8 +1053,8 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG  FileLe
                 */
 
 
-                   pUsData = (USHORT *)&pMailBoxData->data[0];
-                   dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC;
+                   pUsData = (u16 *)&pMailBoxData->data[0];
+                   dpram = (u16)DWNLD_MAG1_PS_HDR_LOC;
                    if (word_length & 0x1)
                        word_length++;
 
@@ -1066,7 +1066,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG  FileLe
 
                       templong = *pUsData++;
                                          templong |= (*pUsData++ << 16);
-                      Status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (PUCHAR)&templong);
+                      Status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (u8 *)&templong);
 
                }
                break;
@@ -1079,10 +1079,10 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG  FileLe
                 * Position ASIC DPRAM auto-increment pointer.
                 */
 
-               pUsFile = (USHORT *)(pFileStart + pFileHdr5->version_data_offset);
+               pUsFile = (u16 *)(pFileStart + pFileHdr5->version_data_offset);
 
 
-                   dpram = (USHORT)DWNLD_MAG1_PS_HDR_LOC;
+                   dpram = (u16)DWNLD_MAG1_PS_HDR_LOC;
                    if (word_length & 0x1)
                        word_length++;
 
@@ -1095,7 +1095,7 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG  FileLe
                       templong = ntohs(*pUsFile++);
                                          temp = ntohs(*pUsFile++);
                                          templong |= (temp << 16);
-                      Status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (PUCHAR)&templong);
+                      Status = fix_ft1000_write_dpram32 (ft1000dev, dpram++, (u8 *)&templong);
 
                }
                break;
@@ -1110,20 +1110,20 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG  FileLe
                for (imageN = 0; imageN < pFileHdr5->nDspImages; imageN++)
                {
 
-                       temp = (USHORT)(pDspImageInfoV6->version);
+                       temp = (u16)(pDspImageInfoV6->version);
                        templong = temp;
-                       temp = (USHORT)(pDspImageInfoV6->version >> 16);
+                       temp = (u16)(pDspImageInfoV6->version >> 16);
                        templong |= (temp << 16);
-                   if (templong == (ULONG)requested_version)
+                   if (templong == (u32)requested_version)
                        {
                            bGoodVersion = TRUE;
                            DEBUG("FT1000:download: bGoodVersion is TRUE\n");
-                           pUsFile = (USHORT *)(pFileStart + pDspImageInfoV6->begin_offset);
-                           pUcFile = (UCHAR *)(pFileStart + pDspImageInfoV6->begin_offset);
-                           pCodeEnd = (UCHAR *)(pFileStart + pDspImageInfoV6->end_offset);
+                           pUsFile = (u16 *)(pFileStart + pDspImageInfoV6->begin_offset);
+                           pUcFile = (u8 *)(pFileStart + pDspImageInfoV6->begin_offset);
+                           pCodeEnd = (u8 *)(pFileStart + pDspImageInfoV6->end_offset);
                            run_address = pDspImageInfoV6->run_address;
                            run_size = pDspImageInfoV6->image_size;
-                           image_chksum = (ULONG)pDspImageInfoV6->checksum;
+                           image_chksum = (u32)pDspImageInfoV6->checksum;
                            break;
                         }
                         pDspImageInfoV6++;
@@ -1181,14 +1181,14 @@ u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG  FileLe
             // Get buffer for provisioning data
                pbuffer = kmalloc((usHdrLength + sizeof(struct pseudo_hdr)), GFP_ATOMIC);
             if (pbuffer) {
-               memcpy(pbuffer, (void *)pUcFile, (UINT)(usHdrLength + sizeof(struct pseudo_hdr)));
+               memcpy(pbuffer, (void *)pUcFile, (u32)(usHdrLength + sizeof(struct pseudo_hdr)));
                 // link provisioning data
                pprov_record = kmalloc(sizeof(struct prov_record), GFP_ATOMIC);
                 if (pprov_record) {
                     pprov_record->pprov_data = pbuffer;
                     list_add_tail (&pprov_record->list, &pft1000info->prov_list);
                     // Move to next entry if available
-                       pUcFile = (UCHAR *)((unsigned long)pUcFile + (UINT)((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr));
+                       pUcFile = (u8 *)((unsigned long)pUcFile + (u32)((usHdrLength + 1) & 0xFFFFFFFE) + sizeof(struct pseudo_hdr));
                     if ( (unsigned long)(pUcFile) - (unsigned long)(pFileStart) >= (unsigned long)FileLength) {
                        uiState = STATE_DONE_FILE;
                     }
index 5b89ee2a2971297d11a39e97b2b9ce813d597d05..b41884e60d073a0ffe49690871500ed819c5c0c6 100644 (file)
@@ -45,33 +45,6 @@ static unsigned long gCardIndex;
 
 #define MAX_RCV_LOOP   100
 
-/****************************************************************
- *     ft1000_control_complete
- ****************************************************************/
-static void ft1000_control_complete(struct urb *urb)
-{
-    struct ft1000_device *ft1000dev = (struct ft1000_device *)urb->context;
-
-    //DEBUG("FT1000_CONTROL_COMPLETE ENTERED\n");
-    if (ft1000dev == NULL )
-    {
-        DEBUG("NULL ft1000dev, failure\n");
-        return ;
-    }
-    else if ( ft1000dev->dev == NULL )
-    {
-        DEBUG("NULL ft1000dev->dev, failure\n");
-        return ;
-    }
-
-    if(waitqueue_active(&ft1000dev->control_wait))
-    {
-        wake_up(&ft1000dev->control_wait);
-    }
-
-    //DEBUG("FT1000_CONTROL_COMPLETE RETURNED\n");
-}
-
 //---------------------------------------------------------------------------
 // Function:    ft1000_control
 //
@@ -187,7 +160,7 @@ u16 ft1000_read_register(struct ft1000_device *ft1000dev, u16* Data, u16 nRegInd
 // Notes:
 //
 //---------------------------------------------------------------------------
-u16 ft1000_write_register(struct ft1000_device *ft1000dev, USHORT value, u16 nRegIndx)
+u16 ft1000_write_register(struct ft1000_device *ft1000dev, u16 value, u16 nRegIndx)
 {
      u16 ret = STATUS_SUCCESS;
 
@@ -223,7 +196,7 @@ u16 ft1000_write_register(struct ft1000_device *ft1000dev, USHORT value, u16 nRe
 //
 //---------------------------------------------------------------------------
 
-u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, USHORT cnt)
+u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, u16 cnt)
 {
     u16 ret = STATUS_SUCCESS;
 
@@ -262,7 +235,7 @@ u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buf
 // Notes:
 //
 //---------------------------------------------------------------------------
-u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, USHORT cnt)
+u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, u16 cnt)
 {
      u16 ret = STATUS_SUCCESS;
 
@@ -299,7 +272,7 @@ u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR bu
 // Notes:
 //
 //---------------------------------------------------------------------------
-u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, u8 highlow)
+u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, u8 highlow)
 {
     u16 ret = STATUS_SUCCESS;
 
@@ -347,7 +320,7 @@ u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buf
 // Notes:
 //
 //---------------------------------------------------------------------------
-u16 ft1000_write_dpram16(struct ft1000_device *ft1000dev, USHORT indx, USHORT value, u8 highlow)
+u16 ft1000_write_dpram16(struct ft1000_device *ft1000dev, u16 indx, u16 value, u8 highlow)
 {
      u16 ret = STATUS_SUCCESS;
 
@@ -392,10 +365,10 @@ u16 ft1000_write_dpram16(struct ft1000_device *ft1000dev, USHORT indx, USHORT va
 // Notes:
 //
 //---------------------------------------------------------------------------
-u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer)
+u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer)
 {
-    UCHAR buf[16];
-    USHORT pos;
+    u8 buf[16];
+    u16 pos;
     u16 ret = STATUS_SUCCESS;
 
     //DEBUG("fix_ft1000_read_dpram32: indx: %d  \n", indx);
@@ -441,14 +414,14 @@ u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR
 // Notes:
 //
 //---------------------------------------------------------------------------
-u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer)
+u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer)
 {
-    USHORT pos1;
-    USHORT pos2;
-    USHORT i;
-    UCHAR buf[32];
-    UCHAR resultbuffer[32];
-    PUCHAR pdata;
+    u16 pos1;
+    u16 pos2;
+    u16 i;
+    u8 buf[32];
+    u8 resultbuffer[32];
+    u8 *pdata;
     u16 ret  = STATUS_SUCCESS;
 
     //DEBUG("fix_ft1000_write_dpram32: Entered:\n");
@@ -472,7 +445,7 @@ u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHA
         return ret;
     }
 
-    ret = ft1000_read_dpram32(ft1000dev, pos1, (PUCHAR)&resultbuffer[0], 16);
+    ret = ft1000_read_dpram32(ft1000dev, pos1, (u8 *)&resultbuffer[0], 16);
     if (ret == STATUS_SUCCESS)
     {
         buffer = pdata;
@@ -487,8 +460,8 @@ u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHA
 
     if (ret == STATUS_FAILURE)
     {
-        ret = ft1000_write_dpram32(ft1000dev, pos1, (PUCHAR)&tempbuffer[0], 16);
-        ret = ft1000_read_dpram32(ft1000dev, pos1, (PUCHAR)&resultbuffer[0], 16);
+        ret = ft1000_write_dpram32(ft1000dev, pos1, (u8 *)&tempbuffer[0], 16);
+        ret = ft1000_read_dpram32(ft1000dev, pos1, (u8 *)&resultbuffer[0], 16);
         if (ret == STATUS_SUCCESS)
         {
             buffer = pdata;
@@ -518,10 +491,10 @@ u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHA
 //
 //  Returns:    None
 //-----------------------------------------------------------------------
-static void card_reset_dsp (struct ft1000_device *ft1000dev, BOOLEAN value)
+static void card_reset_dsp (struct ft1000_device *ft1000dev, bool value)
 {
     u16 status = STATUS_SUCCESS;
-    USHORT tempword;
+    u16 tempword;
 
     status = ft1000_write_register (ft1000dev, HOST_INTF_BE, FT1000_REG_SUP_CTRL);
     status = ft1000_read_register(ft1000dev, &tempword, FT1000_REG_SUP_CTRL);
@@ -620,8 +593,8 @@ void CardSendCommand(struct ft1000_device *ft1000dev, void *ptempbuffer, int siz
 int dsp_reload(struct ft1000_device *ft1000dev)
 {
     u16 status;
-    USHORT tempword;
-    ULONG templong;
+    u16 tempword;
+    u32 templong;
 
        struct ft1000_info *pft1000info;
 
@@ -648,7 +621,7 @@ int dsp_reload(struct ft1000_device *ft1000dev)
     status = ft1000_write_register (ft1000dev, HOST_INTF_BE, FT1000_REG_SUP_CTRL);
 
     // Let's check for FEFE
-    status = ft1000_read_dpram32 (ft1000dev, FT1000_MAG_DPRAM_FEFE_INDX, (PUCHAR)&templong, 4);
+    status = ft1000_read_dpram32 (ft1000dev, FT1000_MAG_DPRAM_FEFE_INDX, (u8 *)&templong, 4);
     DEBUG("templong (fefe) = 0x%8x\n", templong);
 
     // call codeloader
@@ -753,7 +726,7 @@ static int ft1000_reset_card (struct net_device *dev)
 
     // Initialize DSP heartbeat area to ho
     ft1000_write_dpram16(ft1000dev, FT1000_MAG_HI_HO, ho_mag, FT1000_MAG_HI_HO_INDX);
-    ft1000_read_dpram16(ft1000dev, FT1000_MAG_HI_HO, (PCHAR)&tempword, FT1000_MAG_HI_HO_INDX);
+    ft1000_read_dpram16(ft1000dev, FT1000_MAG_HI_HO, (u8 *)&tempword, FT1000_MAG_HI_HO_INDX);
     DEBUG("ft1000_hw:ft1000_reset_card:hi_ho value = 0x%x\n", tempword);
 
 
@@ -874,10 +847,7 @@ u16 init_ft1000_netdev(struct ft1000_device *ft1000dev)
     pInfo->fCondResetPend = 0;
        pInfo->usbboot = 0;
        pInfo->dspalive = 0;
-       for (i=0;i<32 ;i++ )
-       {
-               pInfo->tempbuf[i] = 0;
-       }
+       memset(&pInfo->tempbuf[0], 0, sizeof(pInfo->tempbuf));
 
     INIT_LIST_HEAD(&pInfo->prov_list);
 
@@ -1026,178 +996,6 @@ static void ft1000_usb_transmit_complete(struct urb *urb)
     //DEBUG("Return from ft1000_usb_transmit_complete\n");
 }
 
-
-/****************************************************************
- *     ft1000_control
- ****************************************************************/
-static int ft1000_read_fifo_reg(struct ft1000_device *ft1000dev,unsigned int pipe,
-                          u8 request,
-                          u8 requesttype,
-                          u16 value,
-                          u16 index,
-                          void *data,
-                          u16 size,
-                          int timeout)
-{
-    u16 ret;
-
-    DECLARE_WAITQUEUE(wait, current);
-    struct urb *urb;
-    struct usb_ctrlrequest *dr;
-    int status;
-
-    if (ft1000dev == NULL )
-    {
-        DEBUG("NULL ft1000dev, failure\n");
-        return STATUS_FAILURE;
-    }
-    else if ( ft1000dev->dev == NULL )
-    {
-        DEBUG("NULL ft1000dev->dev, failure\n");
-        return STATUS_FAILURE;
-    }
-
-    spin_lock(&ft1000dev->device_lock);
-
-    if(in_interrupt())
-    {
-        spin_unlock(&ft1000dev->device_lock);
-        return -EBUSY;
-    }
-
-    urb = usb_alloc_urb(0, GFP_KERNEL);
-    dr = kmalloc(sizeof(struct usb_ctrlrequest), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
-
-    if(!urb || !dr)
-    {
-       kfree(dr);
-       usb_free_urb(urb);
-        spin_unlock(&ft1000dev->device_lock);
-        return -ENOMEM;
-    }
-
-
-
-    dr->bRequestType = requesttype;
-    dr->bRequest = request;
-    dr->wValue = value;
-    dr->wIndex = index;
-    dr->wLength = size;
-
-    usb_fill_control_urb(urb, ft1000dev->dev, pipe, (char*)dr, (void*)data, size, (void *)ft1000_control_complete, (void*)ft1000dev);
-
-
-    init_waitqueue_head(&ft1000dev->control_wait);
-
-       set_current_state(TASK_INTERRUPTIBLE);
-
-    add_wait_queue(&ft1000dev->control_wait, &wait);
-
-
-
-
-    status = usb_submit_urb(urb, GFP_KERNEL);
-
-    if(status)
-    {
-        usb_free_urb(urb);
-        kfree(dr);
-        remove_wait_queue(&ft1000dev->control_wait, &wait);
-        spin_unlock(&ft1000dev->device_lock);
-        return status;
-    }
-
-    if(urb->status == -EINPROGRESS)
-    {
-        while(timeout && urb->status == -EINPROGRESS)
-        {
-            status = timeout = schedule_timeout(timeout);
-        }
-    }
-    else
-    {
-        status = 1;
-    }
-
-    remove_wait_queue(&ft1000dev->control_wait, &wait);
-
-    if(!status)
-    {
-        usb_unlink_urb(urb);
-        printk("ft1000 timeout\n");
-        status = -ETIMEDOUT;
-    }
-    else
-    {
-        status = urb->status;
-
-        if(urb->status)
-        {
-            printk("ft1000 control message failed (urb addr: %p) with error number: %i\n", urb, (int)status);
-
-            usb_clear_halt(ft1000dev->dev, usb_rcvctrlpipe(ft1000dev->dev, 0));
-            usb_clear_halt(ft1000dev->dev, usb_sndctrlpipe(ft1000dev->dev, 0));
-            usb_unlink_urb(urb);
-        }
-    }
-
-
-
-    usb_free_urb(urb);
-    kfree(dr);
-    spin_unlock(&ft1000dev->device_lock);
-    return ret;
-
-
-}
-
-//---------------------------------------------------------------------------
-// Function:    ft1000_read_fifo_len
-//
-// Parameters:  ft1000dev - device structure
-//
-//
-// Returns:     none
-//
-// Description: read the fifo length register content
-//
-// Notes:
-//
-//---------------------------------------------------------------------------
-static inline u16 ft1000_read_fifo_len (struct net_device *dev)
-{
-    u16 temp;
-    u16 ret;
-
-       struct ft1000_info *info = (struct ft1000_info *) netdev_priv(dev);
-    struct ft1000_device *ft1000dev = info->pFt1000Dev;
-//    DEBUG("ft1000_read_fifo_len: enter ft1000dev %x\n", ft1000dev);                  //aelias [-] reason: warning: format ???%x??? expects type ???unsigned int???, but argument 2 has type ???struct ft1000_device *???
-    DEBUG("ft1000_read_fifo_len: enter ft1000dev %p\n", ft1000dev);    //aelias [+] reason: up
-
-    ret = STATUS_SUCCESS;
-
-    ret = ft1000_read_fifo_reg(ft1000dev,
-                          usb_rcvctrlpipe(ft1000dev->dev,0),
-                          HARLEY_READ_REGISTER,
-                          HARLEY_READ_OPERATION,
-                          0,
-                          FT1000_REG_MAG_UFSR,
-                          &temp,
-                          2,
-                          LARGE_TIMEOUT);
-
-    if (ret>0)
-        ret = STATUS_SUCCESS;
-    else
-        ret = STATUS_FAILURE;
-
-    DEBUG("ft1000_read_fifo_len: returned %d\n", temp);
-
-    return (temp- 16);
-
-}
-
-
 //---------------------------------------------------------------------------
 //
 // Function:   ft1000_copy_down_pkt
@@ -1219,16 +1017,15 @@ static int ft1000_copy_down_pkt (struct net_device *netdev, u8 *packet, u16 len)
     struct ft1000_device *pFt1000Dev = pInfo->pFt1000Dev;
 
 
-    int i, count, ret;
-    USHORT *pTemp;
-    USHORT checksum;
+       int count, ret;
     u8 *t;
+       struct pseudo_hdr hdr;
 
     if (!pInfo->CardReady)
     {
 
         DEBUG("ft1000_copy_down_pkt::Card Not Ready\n");
-       return STATUS_FAILURE;
+       return -ENODEV;
 
     }
 
@@ -1240,27 +1037,27 @@ static int ft1000_copy_down_pkt (struct net_device *netdev, u8 *packet, u16 len)
     {
         DEBUG("Error:ft1000_copy_down_pkt:Message Size Overflow!\n");
        DEBUG("size = %d\n", count);
-       return STATUS_FAILURE;
+       return -EINVAL;
     }
 
     if ( count % 4)
         count = count + (4- (count %4) );
 
-    pTemp = (PUSHORT)&(pFt1000Dev->tx_buf[0]);
-    *pTemp ++ = ntohs(count);
-    *pTemp ++ = 0x1020;
-    *pTemp ++ = 0x2010;
-    *pTemp ++ = 0x9100;
-    *pTemp ++ = 0;
-    *pTemp ++ = 0;
-    *pTemp ++ = 0;
-    pTemp = (PUSHORT)&(pFt1000Dev->tx_buf[0]);
-    checksum = *pTemp ++;
-    for (i=1; i<7; i++)
-    {
-        checksum ^= *pTemp ++;
-    }
-    *pTemp++ = checksum;
+       memset(&hdr, 0, sizeof(struct pseudo_hdr));
+
+       hdr.length = ntohs(count);
+       hdr.source = 0x10;
+       hdr.destination = 0x20;
+       hdr.portdest = 0x20;
+       hdr.portsrc = 0x10;
+       hdr.sh_str_id = 0x91;
+       hdr.control = 0x00;
+
+       hdr.checksum = hdr.length ^ hdr.source ^ hdr.destination ^
+                       hdr.portdest ^ hdr.portsrc ^ hdr.sh_str_id ^
+                       hdr.control;
+
+       memcpy(&pFt1000Dev->tx_buf[0], &hdr, sizeof(hdr));
        memcpy(&(pFt1000Dev->tx_buf[sizeof(struct pseudo_hdr)]), packet, len);
 
     netif_stop_queue(netdev);
@@ -1283,25 +1080,18 @@ static int ft1000_copy_down_pkt (struct net_device *netdev, u8 *packet, u16 len)
     }*/
 
 
-    ret = usb_submit_urb(pFt1000Dev->tx_urb, GFP_ATOMIC);
-    if(ret)
-    {
+       ret = usb_submit_urb(pFt1000Dev->tx_urb, GFP_ATOMIC);
+       if (ret) {
                DEBUG("ft1000 failed tx_urb %d\n", ret);
-
-               return STATUS_FAILURE;
-
-    }
-    else
-    {
-        //DEBUG("ft1000 sucess tx_urb %d\n", ret);
-
-        pInfo->stats.tx_packets++;
-        pInfo->stats.tx_bytes += (len+14);
-    }
+               return ret;
+       } else {
+               pInfo->stats.tx_packets++;
+               pInfo->stats.tx_bytes += (len+14);
+       }
 
     //DEBUG("ft1000_copy_down_pkt() exit\n");
 
-    return STATUS_SUCCESS;
+       return 0;
 }
 
 //---------------------------------------------------------------------------
@@ -1331,14 +1121,13 @@ static int ft1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
     if ( skb == NULL )
     {
         DEBUG ("ft1000_hw: ft1000_start_xmit:skb == NULL!!!\n" );
-        return STATUS_FAILURE;
+       return NETDEV_TX_OK;
     }
 
     if ( pFt1000Dev->status & FT1000_STATUS_CLOSING)
     {
         DEBUG("network driver is closed, return\n");
-        dev_kfree_skb(skb);
-        return STATUS_SUCCESS;
+       goto err;
     }
 
     //DEBUG("ft1000_start_xmit 1:length of packet = %d\n", skb->len);
@@ -1357,28 +1146,24 @@ static int ft1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
     {
         /* Drop packet is mediastate is down */
         DEBUG("ft1000_hw:ft1000_start_xmit:mediastate is down\n");
-        dev_kfree_skb(skb);
-        return STATUS_SUCCESS;
+       goto err;
     }
 
     if ( (skb->len < ENET_HEADER_SIZE) || (skb->len > ENET_MAX_SIZE) )
     {
         /* Drop packet which has invalid size */
         DEBUG("ft1000_hw:ft1000_start_xmit:invalid ethernet length\n");
-        dev_kfree_skb(skb);
-        return STATUS_SUCCESS;
+       goto err;
     }
 //mbelian
-    if(ft1000_copy_down_pkt (dev, (pdata+ENET_HEADER_SIZE-2), skb->len - ENET_HEADER_SIZE + 2) == STATUS_FAILURE)
-       {
-       dev_kfree_skb(skb);
-               return STATUS_SUCCESS;
-       }
+       ft1000_copy_down_pkt(dev, (pdata+ENET_HEADER_SIZE-2),
+                               skb->len - ENET_HEADER_SIZE + 2);
 
-    dev_kfree_skb(skb);
+err:
+       dev_kfree_skb(skb);
     //DEBUG(" ft1000_start_xmit() exit\n");
 
-    return 0;
+       return NETDEV_TX_OK;
 }
 
 //---------------------------------------------------------------------------
@@ -1424,7 +1209,7 @@ static int ft1000_copy_up_pkt (struct urb *urb)
     //DEBUG("ft1000_copy_up_pkt: transfer_buffer_length=%d, actual_buffer_len=%d\n",
       //       urb->transfer_buffer_length, urb->actual_length);
 
-    chksum = (PUSHORT)ft1000dev->rx_buf;
+    chksum = (u16 *)ft1000dev->rx_buf;
 
     tempword = *chksum++;
     for (i=1; i<7; i++)
@@ -1521,7 +1306,7 @@ static int ft1000_submit_rx_urb(struct ft1000_info *info)
     {
         DEBUG("network driver is closed, return\n");
         //usb_kill_urb(pFt1000Dev->rx_urb); //mbelian
-        return STATUS_SUCCESS;
+       return -ENODEV;
     }
 
     usb_fill_bulk_urb(pFt1000Dev->rx_urb,
@@ -1536,12 +1321,12 @@ static int ft1000_submit_rx_urb(struct ft1000_info *info)
     if((result = usb_submit_urb(pFt1000Dev->rx_urb, GFP_ATOMIC)))
     {
         printk("ft1000_submit_rx_urb: submitting rx_urb %d failed\n", result);
-        return STATUS_FAILURE;
+       return result;
     }
 
     //DEBUG("ft1000_submit_rx_urb exit: result=%d\n", result);
 
-    return STATUS_SUCCESS;
+       return 0;
 }
 
 //---------------------------------------------------------------------------
@@ -1562,6 +1347,7 @@ static int ft1000_open (struct net_device *dev)
 {
        struct ft1000_info *pInfo = (struct ft1000_info *)netdev_priv(dev);
     struct timeval tv; //mbelian
+       int ret;
 
     DEBUG("ft1000_open is called for card %d\n", pInfo->CardNumber);
     //DEBUG("ft1000_open: dev->addr=%x, dev->addr_len=%d\n", dev->addr, dev->addr_len);
@@ -1579,8 +1365,9 @@ static int ft1000_open (struct net_device *dev)
 
     netif_carrier_on(dev); //mbelian
 
-    ft1000_submit_rx_urb(pInfo);
-    return 0;
+       ret = ft1000_submit_rx_urb(pInfo);
+
+       return ret;
 }
 
 //---------------------------------------------------------------------------
@@ -1692,13 +1479,13 @@ static int ft1000_chkcard (struct ft1000_device *dev) {
 //          = 1 (successful)
 //
 //---------------------------------------------------------------------------
-static BOOLEAN ft1000_receive_cmd (struct ft1000_device *dev, u16 *pbuffer, int maxsz, u16 *pnxtph) {
+static bool ft1000_receive_cmd (struct ft1000_device *dev, u16 *pbuffer, int maxsz, u16 *pnxtph) {
     u16 size, ret;
     u16 *ppseudohdr;
     int i;
     u16 tempword;
 
-    ret = ft1000_read_dpram16(dev, FT1000_MAG_PH_LEN, (PUCHAR)&size, FT1000_MAG_PH_LEN_INDX);
+    ret = ft1000_read_dpram16(dev, FT1000_MAG_PH_LEN, (u8 *)&size, FT1000_MAG_PH_LEN_INDX);
     size = ntohs(size) + PSEUDOSZ;
     if (size > maxsz) {
         DEBUG("FT1000:ft1000_receive_cmd:Invalid command length = %d\n", size);
@@ -1754,9 +1541,9 @@ static int ft1000_dsp_prov(void *arg)
     u16 i=0;
        struct prov_record *ptr;
        struct pseudo_hdr *ppseudo_hdr;
-    PUSHORT pmsg;
+    u16 *pmsg;
     u16 status;
-    USHORT TempShortBuf [256];
+    u16 TempShortBuf [256];
 
     DEBUG("*** DspProv Entered\n");
 
@@ -1792,7 +1579,7 @@ static int ft1000_dsp_prov(void *arg)
             len = htons(len);
             len += PSEUDOSZ;
 
-            pmsg = (PUSHORT)ptr->pprov_data;
+            pmsg = (u16 *)ptr->pprov_data;
                ppseudo_hdr = (struct pseudo_hdr *)pmsg;
             // Insert slow queue sequence number
             ppseudo_hdr->seq_num = info->squeseqnum++;
@@ -1809,7 +1596,7 @@ static int ft1000_dsp_prov(void *arg)
             TempShortBuf[1] = htons (len);
             memcpy(&TempShortBuf[2], ppseudo_hdr, len);
 
-            status = ft1000_write_dpram32 (dev, 0, (PUCHAR)&TempShortBuf[0], (unsigned short)(len+2));
+            status = ft1000_write_dpram32 (dev, 0, (u8 *)&TempShortBuf[0], (unsigned short)(len+2));
             status = ft1000_write_register (dev, FT1000_DB_DPRAM_TX, FT1000_REG_DOORBELL);
 
             list_del(&ptr->list);
@@ -1839,7 +1626,7 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) {
        struct drv_msg *pdrvmsg;
     u16 i;
        struct pseudo_hdr *ppseudo_hdr;
-    PUSHORT pmsg;
+    u16 *pmsg;
     u16 status;
     union {
         u8  byte[2];
@@ -1971,7 +1758,7 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) {
                 tempword = ntohs(pdrvmsg->length);
                 info->DSPInfoBlklen = tempword;
                 if (tempword < (MAX_DSP_SESS_REC-4) ) {
-                    pmsg = (PUSHORT)&pdrvmsg->data[0];
+                    pmsg = (u16 *)&pdrvmsg->data[0];
                     for (i=0; i<((tempword+1)/2); i++) {
                         DEBUG("FT1000:drivermsg:dsp info data = 0x%x\n", *pmsg);
                         info->DSPInfoBlk[i+10] = *pmsg++;
@@ -2003,10 +1790,10 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) {
 
                 // Put message into Slow Queue
                 // Form Pseudo header
-                pmsg = (PUSHORT)info->DSPInfoBlk;
+                pmsg = (u16 *)info->DSPInfoBlk;
                 *pmsg++ = 0;
                 *pmsg++ = htons(info->DSPInfoBlklen+20+info->DSPInfoBlklen);
-               ppseudo_hdr = (struct pseudo_hdr *)(PUSHORT)&info->DSPInfoBlk[2];
+               ppseudo_hdr = (struct pseudo_hdr *)(u16 *)&info->DSPInfoBlk[2];
                 ppseudo_hdr->length = htons(info->DSPInfoBlklen+4+info->DSPInfoBlklen);
                 ppseudo_hdr->source = 0x10;
                 ppseudo_hdr->destination = 0x20;
@@ -2028,7 +1815,7 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) {
                 }
                 info->DSPInfoBlk[10] = 0x7200;
                 info->DSPInfoBlk[11] = htons(info->DSPInfoBlklen);
-                status = ft1000_write_dpram32 (dev, 0, (PUCHAR)&info->DSPInfoBlk[0], (unsigned short)(info->DSPInfoBlklen+22));
+                status = ft1000_write_dpram32 (dev, 0, (u8 *)&info->DSPInfoBlk[0], (unsigned short)(info->DSPInfoBlklen+22));
                 status = ft1000_write_register (dev, FT1000_DB_DPRAM_TX, FT1000_REG_DOORBELL);
                 info->DrvMsgPend = 0;
 
@@ -2053,7 +1840,7 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) {
               if ( (tempword & FT1000_DB_DPRAM_TX) == 0) {
                   // Put message into Slow Queue
                   // Form Pseudo header
-                  pmsg = (PUSHORT)&tempbuffer[0];
+                  pmsg = (u16 *)&tempbuffer[0];
                        ppseudo_hdr = (struct pseudo_hdr *)pmsg;
                   ppseudo_hdr->length = htons(0x0012);
                   ppseudo_hdr->source = 0x10;
@@ -2074,7 +1861,7 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) {
                   for (i=1; i<7; i++) {
                       ppseudo_hdr->checksum ^= *pmsg++;
                   }
-                  pmsg = (PUSHORT)&tempbuffer[16];
+                  pmsg = (u16 *)&tempbuffer[16];
                   *pmsg++ = htons(RSP_DRV_ERR_RPT_MSG);
                   *pmsg++ = htons(0x000e);
                   *pmsg++ = htons(info->DSP_TIME[0]);
@@ -2089,7 +1876,7 @@ static int ft1000_proc_drvmsg (struct ft1000_device *dev, u16 size) {
                   *pmsg++ = convert.wrd;
                   *pmsg++ = htons(info->DrvErrNum);
 
-                  CardSendCommand (dev, (unsigned char*)&tempbuffer[0], (USHORT)(0x0012 + PSEUDOSZ));
+                  CardSendCommand (dev, (unsigned char*)&tempbuffer[0], (u16)(0x0012 + PSEUDOSZ));
                   info->DrvErrNum = 0;
               }
               info->DrvMsgPend = 0;
@@ -2120,9 +1907,9 @@ int ft1000_poll(void* dev_id) {
     u16 status;
     u16 size;
     int i;
-    USHORT data;
-    USHORT modulo;
-    USHORT portid;
+    u16 data;
+    u16 modulo;
+    u16 portid;
     u16 nxtph;
        struct dpram_blk *pdpram_blk;
        struct pseudo_hdr *ppseudo_hdr;
@@ -2143,14 +1930,14 @@ int ft1000_poll(void* dev_id) {
         if (tempword & FT1000_DB_DPRAM_RX) {
             //DEBUG("ft1000_poll: FT1000_REG_DOORBELL message type:  FT1000_DB_DPRAM_RX\n");
 
-            status = ft1000_read_dpram16(dev, 0x200, (PUCHAR)&data, 0);
+            status = ft1000_read_dpram16(dev, 0x200, (u8 *)&data, 0);
             //DEBUG("ft1000_poll:FT1000_DB_DPRAM_RX:ft1000_read_dpram16:size = 0x%x\n", data);
             size = ntohs(data) + 16 + 2; //wai
             if (size % 4) {
                 modulo = 4 - (size % 4);
                 size = size + modulo;
             }
-            status = ft1000_read_dpram16(dev, 0x201, (PUCHAR)&portid, 1);
+            status = ft1000_read_dpram16(dev, 0x201, (u8 *)&portid, 1);
             portid &= 0xff;
             //DEBUG("ft1000_poll: FT1000_REG_DOORBELL message type: FT1000_DB_DPRAM_RX : portid 0x%x\n", portid);
 
@@ -2285,7 +2072,7 @@ int ft1000_poll(void* dev_id) {
             status = ft1000_write_register (dev, FT1000_ASIC_RESET_REQ, FT1000_REG_DOORBELL);
             status = ft1000_write_register (dev, HOST_INTF_BE, FT1000_REG_SUP_CTRL);
             // copy dsp session record from Adapter block
-            status = ft1000_write_dpram32 (dev, 0, (PUCHAR)&info->DSPSess.Rec[0], 1024);
+            status = ft1000_write_dpram32 (dev, 0, (u8 *)&info->DSPSess.Rec[0], 1024);
             // Program WMARK register
             status = ft1000_write_register (dev, 0x600, FT1000_REG_MAG_WATERMARK);
             // ring doorbell to tell DSP that ASIC is out of reset
@@ -2299,10 +2086,10 @@ int ft1000_poll(void* dev_id) {
             if (info->fAppMsgPend == 0) {
                // Reset ASIC and DSP
 
-                status    = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER0, (PUCHAR)&(info->DSP_TIME[0]), FT1000_MAG_DSP_TIMER0_INDX);
-                status    = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER1, (PUCHAR)&(info->DSP_TIME[1]), FT1000_MAG_DSP_TIMER1_INDX);
-                status    = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER2, (PUCHAR)&(info->DSP_TIME[2]), FT1000_MAG_DSP_TIMER2_INDX);
-                status    = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER3, (PUCHAR)&(info->DSP_TIME[3]), FT1000_MAG_DSP_TIMER3_INDX);
+                status    = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER0, (u8 *)&(info->DSP_TIME[0]), FT1000_MAG_DSP_TIMER0_INDX);
+                status    = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER1, (u8 *)&(info->DSP_TIME[1]), FT1000_MAG_DSP_TIMER1_INDX);
+                status    = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER2, (u8 *)&(info->DSP_TIME[2]), FT1000_MAG_DSP_TIMER2_INDX);
+                status    = ft1000_read_dpram16(dev, FT1000_MAG_DSP_TIMER3, (u8 *)&(info->DSP_TIME[3]), FT1000_MAG_DSP_TIMER3_INDX);
                 info->CardReady = 0;
                 info->DrvErrNum = DSP_CONDRESET_INFO;
                 DEBUG("ft1000_hw:DSP conditional reset requested\n");
index c580741310140d8b2a28e63b800ee2a291a37020..ab9312f9f3260336673e3f6da225b15a699b6f94 100644 (file)
@@ -4,7 +4,7 @@
 
 #include "ft1000_usb.h"
 
-extern u16 ft1000_read_register(struct usb_device *dev, PUSHORT Data, u8 nRegIndx);
-extern u16 ft1000_write_register(struct usb_device *dev, USHORT value, u8 nRegIndx);
+extern u16 ft1000_read_register(struct usb_device *dev, u16 *Data, u8 nRegIndx);
+extern u16 ft1000_write_register(struct usb_device *dev, u16 value, u8 nRegIndx);
 
 #endif
index 36cdd588fa980786d5b6ee1640461da9c75a19ce..f665640058ae9d90c81694de855ec5d96ab61835 100644 (file)
@@ -38,8 +38,8 @@
 //#endif
 
 
-u16 ft1000_read_dpram16 (struct ft1000_device *ft1000dev, USHORT indx,
-                        PUCHAR buffer, u8 highlow);
+u16 ft1000_read_dpram16 (struct ft1000_device *ft1000dev, u16 indx,
+                        u8 *buffer, u8 highlow);
 
 
 static int
@@ -77,11 +77,11 @@ ft1000ReadProc (char *page, char **start, off_t off, int count, int *eof,
   if (info->ProgConStat != 0xFF)
     {
       ft1000_read_dpram16 (info->pFt1000Dev, FT1000_MAG_DSP_LED,
-                          (PUCHAR) & ledStat, FT1000_MAG_DSP_LED_INDX);
+                          (u8 *)&ledStat, FT1000_MAG_DSP_LED_INDX);
       info->LedStat = ntohs (ledStat);
 
       ft1000_read_dpram16 (info->pFt1000Dev, FT1000_MAG_DSP_CON_STATE,
-                          (PUCHAR) & conStat, FT1000_MAG_DSP_CON_STATE_INDX);
+                          (u8 *)&conStat, FT1000_MAG_DSP_CON_STATE_INDX);
       info->ConStat = ntohs (conStat);
       do_gettimeofday (&tv);
       delta = (tv.tv_sec - info->ConTm);
index 28f55b2030e951f773c5a54a8ce9d7cd1aa2eb36..41bbe991f0dea289326456fc9792334a87468a6c 100644 (file)
@@ -36,7 +36,7 @@ static struct usb_device_id id_table[] = {
 
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static BOOLEAN gPollingfailed = FALSE;
+static bool gPollingfailed = FALSE;
 int ft1000_poll_thread(void *arg)
 {
        int ret = STATUS_SUCCESS;
@@ -84,7 +84,6 @@ static int ft1000_probe(struct usb_interface *interface,
        ft1000dev->dev = dev;
        ft1000dev->status = 0;
        ft1000dev->net = NULL;
-       spin_lock_init(&ft1000dev->device_lock);
        ft1000dev->tx_urb = usb_alloc_urb(0, GFP_ATOMIC);
        ft1000dev->rx_urb = usb_alloc_urb(0, GFP_ATOMIC);
 
index a9d419a98a06f896701640a99a8ec288f5968e2d..a07db26441f18990bc1028c91564315d6f4f5074 100644 (file)
@@ -98,16 +98,6 @@ struct prov_record {
 /*end of Jim*/
 #define DEBUG(args...) printk(KERN_INFO args)
 
-#define UCHAR               u8
-#define USHORT              u16
-#define ULONG               u32 /* WTF ??? */
-#define BOOLEAN             u8
-#define PULONG              u32 *
-#define PUSHORT             u16 *
-#define PUCHAR              u8 *
-#define PCHAR               u8 *
-#define UINT                u32
-
 #define FALSE           0
 #define TRUE            1
 
@@ -372,15 +362,15 @@ struct prov_record {
 
 
 
-#define ISR_EMPTY                      (UCHAR)0x00      // no bits set in ISR
+#define ISR_EMPTY                      (u8)0x00         // no bits set in ISR
 
-#define ISR_DOORBELL_ACK       (UCHAR)0x01              //  the doorbell i sent has been recieved.
+#define ISR_DOORBELL_ACK       (u8)0x01                 //  the doorbell i sent has been recieved.
 
-#define ISR_DOORBELL_PEND      (UCHAR)0x02      //  doorbell for me
+#define ISR_DOORBELL_PEND      (u8)0x02         //  doorbell for me
 
-#define ISR_RCV                                (UCHAR)0x04      // packet received with no errors
+#define ISR_RCV                                (u8)0x04         // packet received with no errors
 
-#define ISR_WATERMARK          (UCHAR)0x08      //
+#define ISR_WATERMARK          (u8)0x08         //
 
 
 
@@ -466,12 +456,9 @@ struct ft1000_device
 {
        struct usb_device *dev;
        struct net_device *net;
-       spinlock_t device_lock;
 
        u32 status;
 
-       wait_queue_head_t control_wait;
-
        struct urb *rx_urb;
        struct urb *tx_urb;
 
@@ -497,9 +484,9 @@ struct ft1000_info {
        unsigned char usbboot;
     unsigned short dspalive;
     u16 ASIC_ID;
-    BOOLEAN fProvComplete;
-    BOOLEAN fCondResetPend;
-    BOOLEAN fAppMsgPend;
+    bool fProvComplete;
+    bool fCondResetPend;
+    bool fAppMsgPend;
     char *pfwimg;
     int fwimgsz;
     u16 DrvErrNum;
@@ -567,20 +554,20 @@ struct dpram_blk {
 } __attribute__ ((packed));
 
 u16 ft1000_read_register(struct ft1000_device *ft1000dev, u16* Data, u16 nRegIndx);
-u16 ft1000_write_register(struct ft1000_device *ft1000dev, USHORT value, u16 nRegIndx);
-u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, USHORT cnt);
-u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, USHORT cnt);
-u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer, u8 highlow);
-u16 ft1000_write_dpram16(struct ft1000_device *ft1000dev, USHORT indx, USHORT value, u8 highlow);
-u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer);
-u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, USHORT indx, PUCHAR buffer);
+u16 ft1000_write_register(struct ft1000_device *ft1000dev, u16 value, u16 nRegIndx);
+u16 ft1000_read_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, u16 cnt);
+u16 ft1000_write_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, u16 cnt);
+u16 ft1000_read_dpram16(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, u8 highlow);
+u16 ft1000_write_dpram16(struct ft1000_device *ft1000dev, u16 indx, u16 value, u8 highlow);
+u16 fix_ft1000_read_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer);
+u16 fix_ft1000_write_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer);
 
 extern void *pFileStart;
 extern size_t FileLength;
 extern int numofmsgbuf;
 
 int ft1000_close (struct net_device *dev);
-u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, ULONG  FileLength);
+u16 scram_dnldr(struct ft1000_device *ft1000dev, void *pFileStart, u32  FileLength);
 
 extern struct list_head freercvpool;
 extern spinlock_t free_buff_lock;   // lock to arbitrate free buffer list for receive command data
index ed48815a916b37b1d5c5ffd2aca810b863276baf..e2ac07d86110488a41fa62c4416953f2627514e4 100644 (file)
@@ -42,11 +42,15 @@ config IIO_TRIGGER
 
 source "drivers/staging/iio/accel/Kconfig"
 source "drivers/staging/iio/adc/Kconfig"
+source "drivers/staging/iio/addac/Kconfig"
+source "drivers/staging/iio/dac/Kconfig"
+source "drivers/staging/iio/dds/Kconfig"
 source "drivers/staging/iio/gyro/Kconfig"
 source "drivers/staging/iio/imu/Kconfig"
 source "drivers/staging/iio/light/Kconfig"
 source "drivers/staging/iio/magnetometer/Kconfig"
-
+source "drivers/staging/iio/meter/Kconfig"
+source "drivers/staging/iio/resolver/Kconfig"
 source "drivers/staging/iio/trigger/Kconfig"
 
 endif # IIO
index e909674920fc4924cfdd98a2c2b69ff2514b3645..f9b5fb2fe8f14ede69d682a61fd653341e225075 100644 (file)
@@ -11,8 +11,13 @@ obj-$(CONFIG_IIO_SW_RING) += ring_sw.o
 
 obj-y += accel/
 obj-y += adc/
+obj-y += addac/
+obj-y += dac/
+obj-y += dds/
 obj-y += gyro/
 obj-y += imu/
 obj-y += light/
-obj-y += trigger/
 obj-y += magnetometer/
+obj-y += meter/
+obj-y += resolver/
+obj-y += trigger/
index 898cba1c939f939299ac16ab3f8dc152662bf01d..d1ad35e24abbbdba7a39a0b4f627fee69e608848 100644 (file)
@@ -61,6 +61,10 @@ necessitate a header that is also visible from arch board
 files. (avoided at the moment to keep the driver set
 contained in staging).
 
+ADI Drivers:
+CC the device-drivers-devel@blackfin.uclinux.org mailing list when
+e-mailing the normal IIO list (see below).
+
 Documentation
 1) Lots of cleanup and expansion.
 2) Some device require indvidual docs.
index 5926c03be1a5fddfb6723ba7c6ba36ded0f89b65..a34f1d3e673ca337952bd49909b7dc3409b298e3 100644 (file)
@@ -3,6 +3,33 @@
 #
 comment "Accelerometers"
 
+config ADIS16201
+       tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer"
+       depends on SPI
+       select IIO_TRIGGER if IIO_RING_BUFFER
+       select IIO_SW_RING if IIO_RING_BUFFER
+       help
+         Say yes here to build support for Analog Devices adis16201 dual-axis
+         digital inclinometer and accelerometer.
+
+config ADIS16203
+       tristate "Analog Devices ADIS16203 Programmable 360 Degrees Inclinometer"
+       depends on SPI
+       select IIO_TRIGGER if IIO_RING_BUFFER
+       select IIO_SW_RING if IIO_RING_BUFFER
+       help
+         Say yes here to build support for Analog Devices adis16203 Programmable
+         360 Degrees Inclinometer.
+
+config ADIS16204
+       tristate "Analog Devices ADIS16204 Programmable High-g Digital Impact Sensor and Recorder"
+       depends on SPI
+       select IIO_TRIGGER if IIO_RING_BUFFER
+       select IIO_SW_RING if IIO_RING_BUFFER
+       help
+         Say yes here to build support for Analog Devices adis16204 Programmable
+         High-g Digital Impact Sensor and Recorder.
+
 config ADIS16209
        tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer"
        depends on SPI
index ff84703a16f6863a039c5354f8a8249c002c9792..1b2a6d3ddafac55c5d64cbf128ada687449ea365 100644 (file)
@@ -2,6 +2,18 @@
 # Makefile for industrial I/O accelerometer drivers
 #
 
+adis16201-y             := adis16201_core.o
+adis16201-$(CONFIG_IIO_RING_BUFFER) += adis16201_ring.o adis16201_trigger.o
+obj-$(CONFIG_ADIS16201) += adis16201.o
+
+adis16203-y             := adis16203_core.o
+adis16203-$(CONFIG_IIO_RING_BUFFER) += adis16203_ring.o adis16203_trigger.o
+obj-$(CONFIG_ADIS16203) += adis16203.o
+
+adis16204-y             := adis16204_core.o
+adis16204-$(CONFIG_IIO_RING_BUFFER) += adis16204_ring.o adis16204_trigger.o
+obj-$(CONFIG_ADIS16204) += adis16204.o
+
 adis16209-y             := adis16209_core.o
 adis16209-$(CONFIG_IIO_RING_BUFFER) += adis16209_ring.o adis16209_trigger.o
 obj-$(CONFIG_ADIS16209) += adis16209.o
index f5f61b2497aa45259bbb7cf8ead056789116819f..50651f835ceaeefceba922459baa553ce03673c5 100644 (file)
 #define IIO_DEV_ATTR_ACCEL_Z(_show, _addr)                     \
        IIO_DEVICE_ATTR(accel_z_raw, S_IRUGO, _show, NULL, _addr)
 
+#define IIO_DEV_ATTR_ACCEL_XY(_show, _addr)                    \
+       IIO_DEVICE_ATTR(accel_xy, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ACCEL_PEAK(_show, _addr)                  \
+       IIO_DEVICE_ATTR(accel_peak, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ACCEL_XPEAK(_show, _addr)                 \
+       IIO_DEVICE_ATTR(accel_xpeak, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ACCEL_YPEAK(_show, _addr)                 \
+       IIO_DEVICE_ATTR(accel_ypeak, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ACCEL_ZPEAK(_show, _addr)                 \
+       IIO_DEVICE_ATTR(accel_zpeak, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ACCEL_XYPEAK(_show, _addr)                \
+       IIO_DEVICE_ATTR(accel_xypeak, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ACCEL_XYZPEAK(_show, _addr)               \
+       IIO_DEVICE_ATTR(accel_xyzpeak, S_IRUGO, _show, NULL, _addr)
diff --git a/drivers/staging/iio/accel/adis16201.h b/drivers/staging/iio/accel/adis16201.h
new file mode 100644 (file)
index 0000000..c9bf22c
--- /dev/null
@@ -0,0 +1,150 @@
+#ifndef SPI_ADIS16201_H_
+#define SPI_ADIS16201_H_
+
+#define ADIS16201_STARTUP_DELAY        220 /* ms */
+
+#define ADIS16201_READ_REG(a)    a
+#define ADIS16201_WRITE_REG(a) ((a) | 0x80)
+
+#define ADIS16201_FLASH_CNT      0x00 /* Flash memory write count */
+#define ADIS16201_SUPPLY_OUT     0x02 /* Output, power supply */
+#define ADIS16201_XACCL_OUT      0x04 /* Output, x-axis accelerometer */
+#define ADIS16201_YACCL_OUT      0x06 /* Output, y-axis accelerometer */
+#define ADIS16201_AUX_ADC        0x08 /* Output, auxiliary ADC input */
+#define ADIS16201_TEMP_OUT       0x0A /* Output, temperature */
+#define ADIS16201_XINCL_OUT      0x0C /* Output, x-axis inclination */
+#define ADIS16201_YINCL_OUT      0x0E /* Output, y-axis inclination */
+#define ADIS16201_XACCL_OFFS     0x10 /* Calibration, x-axis acceleration offset */
+#define ADIS16201_YACCL_OFFS     0x12 /* Calibration, y-axis acceleration offset */
+#define ADIS16201_XACCL_SCALE    0x14 /* x-axis acceleration scale factor */
+#define ADIS16201_YACCL_SCALE    0x16 /* y-axis acceleration scale factor */
+#define ADIS16201_XINCL_OFFS     0x18 /* Calibration, x-axis inclination offset */
+#define ADIS16201_YINCL_OFFS     0x1A /* Calibration, y-axis inclination offset */
+#define ADIS16201_XINCL_SCALE    0x1C /* x-axis inclination scale factor */
+#define ADIS16201_YINCL_SCALE    0x1E /* y-axis inclination scale factor */
+#define ADIS16201_ALM_MAG1       0x20 /* Alarm 1 amplitude threshold */
+#define ADIS16201_ALM_MAG2       0x22 /* Alarm 2 amplitude threshold */
+#define ADIS16201_ALM_SMPL1      0x24 /* Alarm 1, sample period */
+#define ADIS16201_ALM_SMPL2      0x26 /* Alarm 2, sample period */
+#define ADIS16201_ALM_CTRL       0x28 /* Alarm control */
+#define ADIS16201_AUX_DAC        0x30 /* Auxiliary DAC data */
+#define ADIS16201_GPIO_CTRL      0x32 /* General-purpose digital input/output control */
+#define ADIS16201_MSC_CTRL       0x34 /* Miscellaneous control */
+#define ADIS16201_SMPL_PRD       0x36 /* Internal sample period (rate) control */
+#define ADIS16201_AVG_CNT        0x38 /* Operation, filter configuration */
+#define ADIS16201_SLP_CNT        0x3A /* Operation, sleep mode control */
+#define ADIS16201_DIAG_STAT      0x3C /* Diagnostics, system status register */
+#define ADIS16201_GLOB_CMD       0x3E /* Operation, system command register */
+
+#define ADIS16201_OUTPUTS        7
+
+/* MSC_CTRL */
+#define ADIS16201_MSC_CTRL_SELF_TEST_EN                (1 << 8)  /* Self-test enable */
+#define ADIS16201_MSC_CTRL_DATA_RDY_EN         (1 << 2)  /* Data-ready enable: 1 = enabled, 0 = disabled */
+#define ADIS16201_MSC_CTRL_ACTIVE_HIGH         (1 << 1)  /* Data-ready polarity: 1 = active high, 0 = active low */
+#define ADIS16201_MSC_CTRL_DATA_RDY_DIO1       (1 << 0)  /* Data-ready line selection: 1 = DIO1, 0 = DIO0 */
+
+/* DIAG_STAT */
+#define ADIS16201_DIAG_STAT_ALARM2        (1<<9) /* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */
+#define ADIS16201_DIAG_STAT_ALARM1        (1<<8) /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
+#define ADIS16201_DIAG_STAT_SPI_FAIL     (1<<3) /* SPI communications failure */
+#define ADIS16201_DIAG_STAT_FLASH_UPT    (1<<2) /* Flash update failure */
+#define ADIS16201_DIAG_STAT_POWER_HIGH   (1<<1) /* Power supply above 3.625 V */
+#define ADIS16201_DIAG_STAT_POWER_LOW    (1<<0) /* Power supply below 3.15 V */
+
+/* GLOB_CMD */
+#define ADIS16201_GLOB_CMD_SW_RESET    (1<<7)
+#define ADIS16201_GLOB_CMD_FACTORY_CAL (1<<1)
+
+#define ADIS16201_MAX_TX 14
+#define ADIS16201_MAX_RX 14
+
+#define ADIS16201_ERROR_ACTIVE          (1<<14)
+
+/**
+ * struct adis16201_state - device instance specific data
+ * @us:                        actual spi_device
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter:             used to check if new interrupt has been triggered
+ * @last_timestamp:    passing timestamp from th to bh of interrupt handler
+ * @indio_dev:         industrial I/O device structure
+ * @trig:              data ready trigger registered with iio
+ * @tx:                        transmit buffer
+ * @rx:                        recieve buffer
+ * @buf_lock:          mutex to protect tx and rx
+ **/
+struct adis16201_state {
+       struct spi_device               *us;
+       struct work_struct              work_trigger_to_ring;
+       s64                             last_timestamp;
+       struct iio_dev                  *indio_dev;
+       struct iio_trigger              *trig;
+       u8                              *tx;
+       u8                              *rx;
+       struct mutex                    buf_lock;
+};
+
+int adis16201_set_irq(struct device *dev, bool enable);
+
+#ifdef CONFIG_IIO_RING_BUFFER
+enum adis16201_scan {
+       ADIS16201_SCAN_SUPPLY,
+       ADIS16201_SCAN_ACC_X,
+       ADIS16201_SCAN_ACC_Y,
+       ADIS16201_SCAN_AUX_ADC,
+       ADIS16201_SCAN_TEMP,
+       ADIS16201_SCAN_INCLI_X,
+       ADIS16201_SCAN_INCLI_Y,
+};
+
+void adis16201_remove_trigger(struct iio_dev *indio_dev);
+int adis16201_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t adis16201_read_data_from_ring(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf);
+
+int adis16201_configure_ring(struct iio_dev *indio_dev);
+void adis16201_unconfigure_ring(struct iio_dev *indio_dev);
+
+int adis16201_initialize_ring(struct iio_ring_buffer *ring);
+void adis16201_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void adis16201_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16201_probe_trigger(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline ssize_t
+adis16201_read_data_from_ring(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       return 0;
+}
+
+static int adis16201_configure_ring(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline void adis16201_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16201_initialize_ring(struct iio_ring_buffer *ring)
+{
+       return 0;
+}
+
+static inline void adis16201_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+
+#endif /* CONFIG_IIO_RING_BUFFER */
+#endif /* SPI_ADIS16201_H_ */
diff --git a/drivers/staging/iio/accel/adis16201_core.c b/drivers/staging/iio/accel/adis16201_core.c
new file mode 100644 (file)
index 0000000..79b785a
--- /dev/null
@@ -0,0 +1,659 @@
+/*
+ * ADIS16201 Programmable Digital Vibration Sensor driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "accel.h"
+#include "inclinometer.h"
+#include "../gyro/gyro.h"
+#include "../adc/adc.h"
+
+#include "adis16201.h"
+
+#define DRIVER_NAME            "adis16201"
+
+static int adis16201_check_status(struct device *dev);
+
+/**
+ * adis16201_spi_write_reg_8() - write single byte to a register
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the register to be written
+ * @val: the value to write
+ **/
+static int adis16201_spi_write_reg_8(struct device *dev,
+               u8 reg_address,
+               u8 val)
+{
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16201_state *st = iio_dev_get_devdata(indio_dev);
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADIS16201_WRITE_REG(reg_address);
+       st->tx[1] = val;
+
+       ret = spi_write(st->us, st->tx, 2);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+/**
+ * adis16201_spi_write_reg_16() - write 2 bytes to a pair of registers
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the lower of the two registers. Second register
+ *               is assumed to have address one greater.
+ * @val: value to be written
+ **/
+static int adis16201_spi_write_reg_16(struct device *dev,
+               u8 lower_reg_address,
+               u16 value)
+{
+       int ret;
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16201_state *st = iio_dev_get_devdata(indio_dev);
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 2,
+                       .cs_change = 1,
+               }, {
+                       .tx_buf = st->tx + 2,
+                       .bits_per_word = 8,
+                       .len = 2,
+                       .cs_change = 1,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADIS16201_WRITE_REG(lower_reg_address);
+       st->tx[1] = value & 0xFF;
+       st->tx[2] = ADIS16201_WRITE_REG(lower_reg_address + 1);
+       st->tx[3] = (value >> 8) & 0xFF;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfers[0], &msg);
+       spi_message_add_tail(&xfers[1], &msg);
+       ret = spi_sync(st->us, &msg);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+/**
+ * adis16201_spi_read_reg_16() - read 2 bytes from a 16-bit register
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the lower of the two registers. Second register
+ *               is assumed to have address one greater.
+ * @val: somewhere to pass back the value read
+ **/
+static int adis16201_spi_read_reg_16(struct device *dev,
+               u8 lower_reg_address,
+               u16 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16201_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 2,
+                       .cs_change = 1,
+                       .delay_usecs = 20,
+               }, {
+                       .rx_buf = st->rx,
+                       .bits_per_word = 8,
+                       .len = 2,
+                       .cs_change = 1,
+                       .delay_usecs = 20,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADIS16201_READ_REG(lower_reg_address);
+       st->tx[1] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfers[0], &msg);
+       spi_message_add_tail(&xfers[1], &msg);
+       ret = spi_sync(st->us, &msg);
+       if (ret) {
+               dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
+                               lower_reg_address);
+               goto error_ret;
+       }
+       *val = (st->rx[0] << 8) | st->rx[1];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static ssize_t adis16201_read_12bit_unsigned(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u16 val = 0;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = adis16201_spi_read_reg_16(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       if (val & ADIS16201_ERROR_ACTIVE) {
+               ret = adis16201_check_status(dev);
+               if (ret)
+                       return ret;
+       }
+
+       return sprintf(buf, "%u\n", val & 0x0FFF);
+}
+
+static ssize_t adis16201_read_temp(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       ssize_t ret;
+       u16 val;
+
+       /* Take the iio_dev status lock */
+       mutex_lock(&indio_dev->mlock);
+
+       ret = adis16201_spi_read_reg_16(dev, ADIS16201_TEMP_OUT, (u16 *)&val);
+       if (ret)
+               goto error_ret;
+
+       if (val & ADIS16201_ERROR_ACTIVE) {
+               ret = adis16201_check_status(dev);
+               if (ret)
+                       goto error_ret;
+       }
+
+       val &= 0xFFF;
+       ret = sprintf(buf, "%d\n", val);
+
+error_ret:
+       mutex_unlock(&indio_dev->mlock);
+       return ret;
+}
+
+static ssize_t adis16201_read_9bit_signed(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       s16 val = 0;
+       ssize_t ret;
+
+       mutex_lock(&indio_dev->mlock);
+
+       ret = adis16201_spi_read_reg_16(dev, this_attr->address, (u16 *)&val);
+       if (!ret) {
+               if (val & ADIS16201_ERROR_ACTIVE) {
+                       ret = adis16201_check_status(dev);
+                       if (ret)
+                               goto error_ret;
+               }
+               val = ((s16)(val << 7) >> 7);
+               ret = sprintf(buf, "%d\n", val);
+       }
+
+error_ret:
+       mutex_unlock(&indio_dev->mlock);
+
+       return ret;
+}
+
+static ssize_t adis16201_read_12bit_signed(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       s16 val = 0;
+       ssize_t ret;
+
+       mutex_lock(&indio_dev->mlock);
+
+       ret = adis16201_spi_read_reg_16(dev, this_attr->address, (u16 *)&val);
+       if (!ret) {
+               if (val & ADIS16201_ERROR_ACTIVE) {
+                       ret = adis16201_check_status(dev);
+                       if (ret)
+                               goto error_ret;
+               }
+
+               val = ((s16)(val << 4) >> 4);
+               ret = sprintf(buf, "%d\n", val);
+       }
+
+error_ret:
+       mutex_unlock(&indio_dev->mlock);
+
+       return ret;
+}
+
+static ssize_t adis16201_read_14bit_signed(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       s16 val = 0;
+       ssize_t ret;
+
+       mutex_lock(&indio_dev->mlock);
+
+       ret = adis16201_spi_read_reg_16(dev, this_attr->address, (u16 *)&val);
+       if (!ret) {
+               if (val & ADIS16201_ERROR_ACTIVE) {
+                       ret = adis16201_check_status(dev);
+                       if (ret)
+                               goto error_ret;
+               }
+
+               val = ((s16)(val << 2) >> 2);
+               ret = sprintf(buf, "%d\n", val);
+       }
+
+error_ret:
+       mutex_unlock(&indio_dev->mlock);
+
+       return ret;
+}
+
+static ssize_t adis16201_write_16bit(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       int ret;
+       long val;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               goto error_ret;
+       ret = adis16201_spi_write_reg_16(dev, this_attr->address, val);
+
+error_ret:
+       return ret ? ret : len;
+}
+
+static int adis16201_reset(struct device *dev)
+{
+       int ret;
+       ret = adis16201_spi_write_reg_8(dev,
+                       ADIS16201_GLOB_CMD,
+                       ADIS16201_GLOB_CMD_SW_RESET);
+       if (ret)
+               dev_err(dev, "problem resetting device");
+
+       return ret;
+}
+
+static ssize_t adis16201_write_reset(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf, size_t len)
+{
+       if (len < 1)
+               return -EINVAL;
+       switch (buf[0]) {
+       case '1':
+       case 'y':
+       case 'Y':
+               return adis16201_reset(dev);
+       }
+       return -EINVAL;
+}
+
+int adis16201_set_irq(struct device *dev, bool enable)
+{
+       int ret = 0;
+       u16 msc;
+
+       ret = adis16201_spi_read_reg_16(dev, ADIS16201_MSC_CTRL, &msc);
+       if (ret)
+               goto error_ret;
+
+       msc |= ADIS16201_MSC_CTRL_ACTIVE_HIGH;
+       msc &= ~ADIS16201_MSC_CTRL_DATA_RDY_DIO1;
+       if (enable)
+               msc |= ADIS16201_MSC_CTRL_DATA_RDY_EN;
+       else
+               msc &= ~ADIS16201_MSC_CTRL_DATA_RDY_EN;
+
+       ret = adis16201_spi_write_reg_16(dev, ADIS16201_MSC_CTRL, msc);
+
+error_ret:
+       return ret;
+}
+
+static int adis16201_check_status(struct device *dev)
+{
+       u16 status;
+       int ret;
+
+       ret = adis16201_spi_read_reg_16(dev, ADIS16201_DIAG_STAT, &status);
+       if (ret < 0) {
+               dev_err(dev, "Reading status failed\n");
+               goto error_ret;
+       }
+       ret = status & 0xF;
+       if (ret)
+               ret = -EFAULT;
+
+       if (status & ADIS16201_DIAG_STAT_SPI_FAIL)
+               dev_err(dev, "SPI failure\n");
+       if (status & ADIS16201_DIAG_STAT_FLASH_UPT)
+               dev_err(dev, "Flash update failed\n");
+       if (status & ADIS16201_DIAG_STAT_POWER_HIGH)
+               dev_err(dev, "Power supply above 3.625V\n");
+       if (status & ADIS16201_DIAG_STAT_POWER_LOW)
+               dev_err(dev, "Power supply below 3.15V\n");
+
+error_ret:
+       return ret;
+}
+
+static int adis16201_self_test(struct device *dev)
+{
+       int ret;
+       ret = adis16201_spi_write_reg_16(dev,
+                       ADIS16201_MSC_CTRL,
+                       ADIS16201_MSC_CTRL_SELF_TEST_EN);
+       if (ret) {
+               dev_err(dev, "problem starting self test");
+               goto err_ret;
+       }
+
+       ret = adis16201_check_status(dev);
+
+err_ret:
+       return ret;
+}
+
+static int adis16201_initial_setup(struct adis16201_state *st)
+{
+       int ret;
+       struct device *dev = &st->indio_dev->dev;
+
+       /* Disable IRQ */
+       ret = adis16201_set_irq(dev, false);
+       if (ret) {
+               dev_err(dev, "disable irq failed");
+               goto err_ret;
+       }
+
+       /* Do self test */
+       ret = adis16201_self_test(dev);
+       if (ret) {
+               dev_err(dev, "self test failure");
+               goto err_ret;
+       }
+
+       /* Read status register to check the result */
+       ret = adis16201_check_status(dev);
+       if (ret) {
+               adis16201_reset(dev);
+               dev_err(dev, "device not playing ball -> reset");
+               msleep(ADIS16201_STARTUP_DELAY);
+               ret = adis16201_check_status(dev);
+               if (ret) {
+                       dev_err(dev, "giving up");
+                       goto err_ret;
+               }
+       }
+
+       printk(KERN_INFO DRIVER_NAME ": at CS%d (irq %d)\n",
+                       st->us->chip_select, st->us->irq);
+
+err_ret:
+       return ret;
+}
+
+static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16201_read_12bit_unsigned,
+               ADIS16201_SUPPLY_OUT);
+static IIO_CONST_ATTR(in0_supply_scale, "0.00122");
+static IIO_DEV_ATTR_IN_RAW(1, adis16201_read_12bit_unsigned,
+               ADIS16201_AUX_ADC);
+static IIO_CONST_ATTR(in1_scale, "0.00061");
+
+static IIO_DEV_ATTR_ACCEL_X(adis16201_read_14bit_signed,
+               ADIS16201_XACCL_OUT);
+static IIO_DEV_ATTR_ACCEL_Y(adis16201_read_14bit_signed,
+               ADIS16201_YACCL_OUT);
+static IIO_DEV_ATTR_ACCEL_X_OFFSET(S_IWUSR | S_IRUGO,
+               adis16201_read_12bit_signed,
+               adis16201_write_16bit,
+               ADIS16201_XACCL_OFFS);
+static IIO_DEV_ATTR_ACCEL_Y_OFFSET(S_IWUSR | S_IRUGO,
+               adis16201_read_12bit_signed,
+               adis16201_write_16bit,
+               ADIS16201_YACCL_OFFS);
+static IIO_CONST_ATTR(accel_scale, "0.4625");
+
+static IIO_DEV_ATTR_INCLI_X(adis16201_read_14bit_signed,
+               ADIS16201_XINCL_OUT);
+static IIO_DEV_ATTR_INCLI_Y(adis16201_read_14bit_signed,
+               ADIS16201_YINCL_OUT);
+static IIO_DEV_ATTR_INCLI_X_OFFSET(S_IWUSR | S_IRUGO,
+               adis16201_read_9bit_signed,
+               adis16201_write_16bit,
+               ADIS16201_XACCL_OFFS);
+static IIO_DEV_ATTR_INCLI_Y_OFFSET(S_IWUSR | S_IRUGO,
+               adis16201_read_9bit_signed,
+               adis16201_write_16bit,
+               ADIS16201_YACCL_OFFS);
+static IIO_CONST_ATTR(incli_scale, "0.1");
+
+static IIO_DEV_ATTR_TEMP_RAW(adis16201_read_temp);
+static IIO_CONST_ATTR(temp_offset, "25");
+static IIO_CONST_ATTR(temp_scale, "-0.47");
+
+static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16201_write_reset, 0);
+
+static IIO_CONST_ATTR(name, "adis16201");
+
+static struct attribute *adis16201_event_attributes[] = {
+       NULL
+};
+
+static struct attribute_group adis16201_event_attribute_group = {
+       .attrs = adis16201_event_attributes,
+};
+
+static struct attribute *adis16201_attributes[] = {
+       &iio_dev_attr_in0_supply_raw.dev_attr.attr,
+       &iio_const_attr_in0_supply_scale.dev_attr.attr,
+       &iio_dev_attr_temp_raw.dev_attr.attr,
+       &iio_const_attr_temp_offset.dev_attr.attr,
+       &iio_const_attr_temp_scale.dev_attr.attr,
+       &iio_dev_attr_reset.dev_attr.attr,
+       &iio_const_attr_name.dev_attr.attr,
+       &iio_dev_attr_in1_raw.dev_attr.attr,
+       &iio_const_attr_in1_scale.dev_attr.attr,
+       &iio_dev_attr_accel_x_raw.dev_attr.attr,
+       &iio_dev_attr_accel_y_raw.dev_attr.attr,
+       &iio_dev_attr_accel_x_offset.dev_attr.attr,
+       &iio_dev_attr_accel_y_offset.dev_attr.attr,
+       &iio_const_attr_accel_scale.dev_attr.attr,
+       &iio_dev_attr_incli_x_raw.dev_attr.attr,
+       &iio_dev_attr_incli_y_raw.dev_attr.attr,
+       &iio_dev_attr_incli_x_offset.dev_attr.attr,
+       &iio_dev_attr_incli_y_offset.dev_attr.attr,
+       &iio_const_attr_incli_scale.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group adis16201_attribute_group = {
+       .attrs = adis16201_attributes,
+};
+
+static int __devinit adis16201_probe(struct spi_device *spi)
+{
+       int ret, regdone = 0;
+       struct adis16201_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+       if (!st) {
+               ret =  -ENOMEM;
+               goto error_ret;
+       }
+       /* this is only used for removal purposes */
+       spi_set_drvdata(spi, st);
+
+       /* Allocate the comms buffers */
+       st->rx = kzalloc(sizeof(*st->rx)*ADIS16201_MAX_RX, GFP_KERNEL);
+       if (st->rx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->tx = kzalloc(sizeof(*st->tx)*ADIS16201_MAX_TX, GFP_KERNEL);
+       if (st->tx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_rx;
+       }
+       st->us = spi;
+       mutex_init(&st->buf_lock);
+       /* setup the industrialio driver allocated elements */
+       st->indio_dev = iio_allocate_device();
+       if (st->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_tx;
+       }
+
+       st->indio_dev->dev.parent = &spi->dev;
+       st->indio_dev->num_interrupt_lines = 1;
+       st->indio_dev->event_attrs = &adis16201_event_attribute_group;
+       st->indio_dev->attrs = &adis16201_attribute_group;
+       st->indio_dev->dev_data = (void *)(st);
+       st->indio_dev->driver_module = THIS_MODULE;
+       st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = adis16201_configure_ring(st->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       ret = iio_device_register(st->indio_dev);
+       if (ret)
+               goto error_unreg_ring_funcs;
+       regdone = 1;
+
+       ret = adis16201_initialize_ring(st->indio_dev->ring);
+       if (ret) {
+               printk(KERN_ERR "failed to initialize the ring\n");
+               goto error_unreg_ring_funcs;
+       }
+
+       if (spi->irq) {
+               ret = iio_register_interrupt_line(spi->irq,
+                               st->indio_dev,
+                               0,
+                               IRQF_TRIGGER_RISING,
+                               "adis16201");
+               if (ret)
+                       goto error_uninitialize_ring;
+
+               ret = adis16201_probe_trigger(st->indio_dev);
+               if (ret)
+                       goto error_unregister_line;
+       }
+
+       /* Get the device into a sane initial state */
+       ret = adis16201_initial_setup(st);
+       if (ret)
+               goto error_remove_trigger;
+       return 0;
+
+error_remove_trigger:
+       adis16201_remove_trigger(st->indio_dev);
+error_unregister_line:
+       if (spi->irq)
+               iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+       adis16201_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+       adis16201_unconfigure_ring(st->indio_dev);
+error_free_dev:
+       if (regdone)
+               iio_device_unregister(st->indio_dev);
+       else
+               iio_free_device(st->indio_dev);
+error_free_tx:
+       kfree(st->tx);
+error_free_rx:
+       kfree(st->rx);
+error_free_st:
+       kfree(st);
+error_ret:
+       return ret;
+}
+
+static int adis16201_remove(struct spi_device *spi)
+{
+       struct adis16201_state *st = spi_get_drvdata(spi);
+       struct iio_dev *indio_dev = st->indio_dev;
+
+       flush_scheduled_work();
+
+       adis16201_remove_trigger(indio_dev);
+       if (spi->irq)
+               iio_unregister_interrupt_line(indio_dev, 0);
+
+       adis16201_uninitialize_ring(indio_dev->ring);
+       iio_device_unregister(indio_dev);
+       adis16201_unconfigure_ring(indio_dev);
+       kfree(st->tx);
+       kfree(st->rx);
+       kfree(st);
+
+       return 0;
+}
+
+static struct spi_driver adis16201_driver = {
+       .driver = {
+               .name = "adis16201",
+               .owner = THIS_MODULE,
+       },
+       .probe = adis16201_probe,
+       .remove = __devexit_p(adis16201_remove),
+};
+
+static __init int adis16201_init(void)
+{
+       return spi_register_driver(&adis16201_driver);
+}
+module_init(adis16201_init);
+
+static __exit void adis16201_exit(void)
+{
+       spi_unregister_driver(&adis16201_driver);
+}
+module_exit(adis16201_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADIS16201 Programmable Digital Vibration Sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/accel/adis16201_ring.c b/drivers/staging/iio/accel/adis16201_ring.c
new file mode 100644 (file)
index 0000000..e6870a2
--- /dev/null
@@ -0,0 +1,218 @@
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../ring_sw.h"
+#include "accel.h"
+#include "../trigger.h"
+#include "adis16201.h"
+
+static IIO_SCAN_EL_C(in_supply, ADIS16201_SCAN_SUPPLY, ADIS16201_SUPPLY_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(in_supply, u, 12, 16);
+static IIO_SCAN_EL_C(accel_x, ADIS16201_SCAN_ACC_X, ADIS16201_XACCL_OUT, NULL);
+static IIO_SCAN_EL_C(accel_y, ADIS16201_SCAN_ACC_Y, ADIS16201_YACCL_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(accel, s, 14, 16);
+static IIO_SCAN_EL_C(in0, ADIS16201_SCAN_AUX_ADC, ADIS16201_AUX_ADC, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(in0, u, 12, 16);
+static IIO_SCAN_EL_C(temp, ADIS16201_SCAN_TEMP, ADIS16201_TEMP_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(temp, u, 12, 16);
+static IIO_SCAN_EL_C(incli_x, ADIS16201_SCAN_INCLI_X,
+                    ADIS16201_XINCL_OUT, NULL);
+static IIO_SCAN_EL_C(incli_y, ADIS16201_SCAN_INCLI_Y,
+                    ADIS16201_YINCL_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(incli, s, 14, 16);
+static IIO_SCAN_EL_TIMESTAMP(7);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64);
+
+static struct attribute *adis16201_scan_el_attrs[] = {
+       &iio_scan_el_in_supply.dev_attr.attr,
+       &iio_const_attr_in_supply_index.dev_attr.attr,
+       &iio_const_attr_in_supply_type.dev_attr.attr,
+       &iio_scan_el_accel_x.dev_attr.attr,
+       &iio_const_attr_accel_x_index.dev_attr.attr,
+       &iio_scan_el_accel_y.dev_attr.attr,
+       &iio_const_attr_accel_y_index.dev_attr.attr,
+       &iio_const_attr_accel_type.dev_attr.attr,
+       &iio_scan_el_in0.dev_attr.attr,
+       &iio_const_attr_in0_index.dev_attr.attr,
+       &iio_const_attr_in0_type.dev_attr.attr,
+       &iio_scan_el_temp.dev_attr.attr,
+       &iio_const_attr_temp_index.dev_attr.attr,
+       &iio_const_attr_temp_type.dev_attr.attr,
+       &iio_scan_el_incli_x.dev_attr.attr,
+       &iio_const_attr_incli_x_index.dev_attr.attr,
+       &iio_scan_el_incli_y.dev_attr.attr,
+       &iio_const_attr_incli_y_index.dev_attr.attr,
+       &iio_const_attr_incli_type.dev_attr.attr,
+       &iio_scan_el_timestamp.dev_attr.attr,
+       &iio_const_attr_timestamp_index.dev_attr.attr,
+       &iio_const_attr_timestamp_type.dev_attr.attr,
+       NULL,
+};
+
+static struct attribute_group adis16201_scan_el_group = {
+       .attrs = adis16201_scan_el_attrs,
+       .name = "scan_elements",
+};
+
+/**
+ * adis16201_poll_func_th() top half interrupt handler called by trigger
+ * @private_data:      iio_dev
+ **/
+static void adis16201_poll_func_th(struct iio_dev *indio_dev, s64 time)
+{
+       struct adis16201_state *st = iio_dev_get_devdata(indio_dev);
+       st->last_timestamp = time;
+       schedule_work(&st->work_trigger_to_ring);
+}
+
+/**
+ * adis16201_read_ring_data() read data registers which will be placed into ring
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @rx: somewhere to pass back the value read
+ **/
+static int adis16201_read_ring_data(struct device *dev, u8 *rx)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16201_state *st = iio_dev_get_devdata(indio_dev);
+       struct spi_transfer xfers[ADIS16201_OUTPUTS + 1];
+       int ret;
+       int i;
+
+       mutex_lock(&st->buf_lock);
+
+       spi_message_init(&msg);
+
+       memset(xfers, 0, sizeof(xfers));
+       for (i = 0; i <= ADIS16201_OUTPUTS; i++) {
+               xfers[i].bits_per_word = 8;
+               xfers[i].cs_change = 1;
+               xfers[i].len = 2;
+               xfers[i].delay_usecs = 20;
+               xfers[i].tx_buf = st->tx + 2 * i;
+               st->tx[2 * i] = ADIS16201_READ_REG(ADIS16201_SUPPLY_OUT + 2 * i);
+               st->tx[2 * i + 1] = 0;
+               if (i >= 1)
+                       xfers[i].rx_buf = rx + 2 * (i - 1);
+               spi_message_add_tail(&xfers[i], &msg);
+       }
+
+       ret = spi_sync(st->us, &msg);
+       if (ret)
+               dev_err(&st->us->dev, "problem when burst reading");
+
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
+ * specific to be rolled into the core.
+ */
+static void adis16201_trigger_bh_to_ring(struct work_struct *work_s)
+{
+       struct adis16201_state *st
+               = container_of(work_s, struct adis16201_state,
+                              work_trigger_to_ring);
+       struct iio_ring_buffer *ring = st->indio_dev->ring;
+
+       int i = 0;
+       s16 *data;
+       size_t datasize = ring->access.get_bytes_per_datum(ring);
+
+       data = kmalloc(datasize, GFP_KERNEL);
+       if (data == NULL) {
+               dev_err(&st->us->dev, "memory alloc failed in ring bh");
+               return;
+       }
+
+       if (ring->scan_count)
+               if (adis16201_read_ring_data(&st->indio_dev->dev, st->rx) >= 0)
+                       for (; i < ring->scan_count; i++)
+                               data[i] = be16_to_cpup(
+                                       (__be16 *)&(st->rx[i*2]));
+
+       /* Guaranteed to be aligned with 8 byte boundary */
+       if (ring->scan_timestamp)
+               *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp;
+
+       ring->access.store_to(ring,
+                             (u8 *)data,
+                             st->last_timestamp);
+
+       iio_trigger_notify_done(st->indio_dev->trig);
+       kfree(data);
+
+       return;
+}
+
+void adis16201_unconfigure_ring(struct iio_dev *indio_dev)
+{
+       kfree(indio_dev->pollfunc);
+       iio_sw_rb_free(indio_dev->ring);
+}
+
+int adis16201_configure_ring(struct iio_dev *indio_dev)
+{
+       int ret = 0;
+       struct adis16201_state *st = indio_dev->dev_data;
+       struct iio_ring_buffer *ring;
+       INIT_WORK(&st->work_trigger_to_ring, adis16201_trigger_bh_to_ring);
+
+       ring = iio_sw_rb_allocate(indio_dev);
+       if (!ring) {
+               ret = -ENOMEM;
+               return ret;
+       }
+       indio_dev->ring = ring;
+       /* Effectively select the ring buffer implementation */
+       iio_ring_sw_register_funcs(&ring->access);
+       ring->bpe = 2;
+       ring->scan_el_attrs = &adis16201_scan_el_group;
+       ring->scan_timestamp = true;
+       ring->preenable = &iio_sw_ring_preenable;
+       ring->postenable = &iio_triggered_ring_postenable;
+       ring->predisable = &iio_triggered_ring_predisable;
+       ring->owner = THIS_MODULE;
+
+       /* Set default scan mode */
+       iio_scan_mask_set(ring, iio_scan_el_in_supply.number);
+       iio_scan_mask_set(ring, iio_scan_el_accel_x.number);
+       iio_scan_mask_set(ring, iio_scan_el_accel_y.number);
+       iio_scan_mask_set(ring, iio_scan_el_temp.number);
+       iio_scan_mask_set(ring, iio_scan_el_in0.number);
+       iio_scan_mask_set(ring, iio_scan_el_incli_x.number);
+       iio_scan_mask_set(ring, iio_scan_el_incli_y.number);
+
+       ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16201_poll_func_th);
+       if (ret)
+               goto error_iio_sw_rb_free;
+
+       indio_dev->modes |= INDIO_RING_TRIGGERED;
+       return 0;
+
+error_iio_sw_rb_free:
+       iio_sw_rb_free(indio_dev->ring);
+       return ret;
+}
+
+int adis16201_initialize_ring(struct iio_ring_buffer *ring)
+{
+       return iio_ring_buffer_register(ring, 0);
+}
+
+void adis16201_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+       iio_ring_buffer_unregister(ring);
+}
diff --git a/drivers/staging/iio/accel/adis16201_trigger.c b/drivers/staging/iio/accel/adis16201_trigger.c
new file mode 100644 (file)
index 0000000..8a9cea1
--- /dev/null
@@ -0,0 +1,122 @@
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../trigger.h"
+#include "adis16201.h"
+
+/**
+ * adis16201_data_rdy_trig_poll() the event handler for the data rdy trig
+ **/
+static int adis16201_data_rdy_trig_poll(struct iio_dev *dev_info,
+                                      int index,
+                                      s64 timestamp,
+                                      int no_test)
+{
+       struct adis16201_state *st = iio_dev_get_devdata(dev_info);
+       struct iio_trigger *trig = st->trig;
+
+       iio_trigger_poll(trig, timestamp);
+
+       return IRQ_HANDLED;
+}
+
+IIO_EVENT_SH(data_rdy_trig, &adis16201_data_rdy_trig_poll);
+
+static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL);
+
+static struct attribute *adis16201_trigger_attrs[] = {
+       &dev_attr_name.attr,
+       NULL,
+};
+
+static const struct attribute_group adis16201_trigger_attr_group = {
+       .attrs = adis16201_trigger_attrs,
+};
+
+/**
+ * adis16201_data_rdy_trigger_set_state() set datardy interrupt state
+ **/
+static int adis16201_data_rdy_trigger_set_state(struct iio_trigger *trig,
+                                               bool state)
+{
+       struct adis16201_state *st = trig->private_data;
+       struct iio_dev *indio_dev = st->indio_dev;
+       int ret = 0;
+
+       dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state);
+       ret = adis16201_set_irq(&st->indio_dev->dev, state);
+       if (state == false) {
+               iio_remove_event_from_list(&iio_event_data_rdy_trig,
+                                          &indio_dev->interrupts[0]
+                                          ->ev_list);
+               flush_scheduled_work();
+       } else {
+               iio_add_event_to_list(&iio_event_data_rdy_trig,
+                                     &indio_dev->interrupts[0]->ev_list);
+       }
+       return ret;
+}
+
+/**
+ * adis16201_trig_try_reen() try renabling irq for data rdy trigger
+ * @trig:      the datardy trigger
+ **/
+static int adis16201_trig_try_reen(struct iio_trigger *trig)
+{
+       struct adis16201_state *st = trig->private_data;
+       enable_irq(st->us->irq);
+       return 0;
+}
+
+int adis16201_probe_trigger(struct iio_dev *indio_dev)
+{
+       int ret;
+       struct adis16201_state *st = indio_dev->dev_data;
+
+       st->trig = iio_allocate_trigger();
+       st->trig->name = kasprintf(GFP_KERNEL,
+                               "adis16201-dev%d",
+                               indio_dev->id);
+       if (!st->trig->name) {
+               ret = -ENOMEM;
+               goto error_free_trig;
+       }
+       st->trig->dev.parent = &st->us->dev;
+       st->trig->owner = THIS_MODULE;
+       st->trig->private_data = st;
+       st->trig->set_trigger_state = &adis16201_data_rdy_trigger_set_state;
+       st->trig->try_reenable = &adis16201_trig_try_reen;
+       st->trig->control_attrs = &adis16201_trigger_attr_group;
+       ret = iio_trigger_register(st->trig);
+
+       /* select default trigger */
+       indio_dev->trig = st->trig;
+       if (ret)
+               goto error_free_trig_name;
+
+       return 0;
+
+error_free_trig_name:
+       kfree(st->trig->name);
+error_free_trig:
+       iio_free_trigger(st->trig);
+
+       return ret;
+}
+
+void adis16201_remove_trigger(struct iio_dev *indio_dev)
+{
+       struct adis16201_state *state = indio_dev->dev_data;
+
+       iio_trigger_unregister(state->trig);
+       kfree(state->trig->name);
+       iio_free_trigger(state->trig);
+}
diff --git a/drivers/staging/iio/accel/adis16203.h b/drivers/staging/iio/accel/adis16203.h
new file mode 100644 (file)
index 0000000..b39323e
--- /dev/null
@@ -0,0 +1,143 @@
+#ifndef SPI_ADIS16203_H_
+#define SPI_ADIS16203_H_
+
+#define ADIS16203_STARTUP_DELAY        220 /* ms */
+
+#define ADIS16203_READ_REG(a)    a
+#define ADIS16203_WRITE_REG(a) ((a) | 0x80)
+
+#define ADIS16203_FLASH_CNT      0x00 /* Flash memory write count */
+#define ADIS16203_SUPPLY_OUT     0x02 /* Output, power supply */
+#define ADIS16203_AUX_ADC        0x08 /* Output, auxiliary ADC input */
+#define ADIS16203_TEMP_OUT       0x0A /* Output, temperature */
+#define ADIS16203_XINCL_OUT      0x0C /* Output, x-axis inclination */
+#define ADIS16203_YINCL_OUT      0x0E /* Output, y-axis inclination */
+#define ADIS16203_INCL_NULL      0x18 /* Incline null calibration */
+#define ADIS16203_ALM_MAG1       0x20 /* Alarm 1 amplitude threshold */
+#define ADIS16203_ALM_MAG2       0x22 /* Alarm 2 amplitude threshold */
+#define ADIS16203_ALM_SMPL1      0x24 /* Alarm 1, sample period */
+#define ADIS16203_ALM_SMPL2      0x26 /* Alarm 2, sample period */
+#define ADIS16203_ALM_CTRL       0x28 /* Alarm control */
+#define ADIS16203_AUX_DAC        0x30 /* Auxiliary DAC data */
+#define ADIS16203_GPIO_CTRL      0x32 /* General-purpose digital input/output control */
+#define ADIS16203_MSC_CTRL       0x34 /* Miscellaneous control */
+#define ADIS16203_SMPL_PRD       0x36 /* Internal sample period (rate) control */
+#define ADIS16203_AVG_CNT        0x38 /* Operation, filter configuration */
+#define ADIS16203_SLP_CNT        0x3A /* Operation, sleep mode control */
+#define ADIS16203_DIAG_STAT      0x3C /* Diagnostics, system status register */
+#define ADIS16203_GLOB_CMD       0x3E /* Operation, system command register */
+
+#define ADIS16203_OUTPUTS        5
+
+/* MSC_CTRL */
+#define ADIS16203_MSC_CTRL_PWRUP_SELF_TEST     (1 << 10) /* Self-test at power-on: 1 = disabled, 0 = enabled */
+#define ADIS16203_MSC_CTRL_REVERSE_ROT_EN      (1 << 9)  /* Reverses rotation of both inclination outputs */
+#define ADIS16203_MSC_CTRL_SELF_TEST_EN                (1 << 8)  /* Self-test enable */
+#define ADIS16203_MSC_CTRL_DATA_RDY_EN         (1 << 2)  /* Data-ready enable: 1 = enabled, 0 = disabled */
+#define ADIS16203_MSC_CTRL_ACTIVE_HIGH         (1 << 1)  /* Data-ready polarity: 1 = active high, 0 = active low */
+#define ADIS16203_MSC_CTRL_DATA_RDY_DIO1       (1 << 0)  /* Data-ready line selection: 1 = DIO1, 0 = DIO0 */
+
+/* DIAG_STAT */
+#define ADIS16203_DIAG_STAT_ALARM2        (1<<9) /* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */
+#define ADIS16203_DIAG_STAT_ALARM1        (1<<8) /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
+#define ADIS16203_DIAG_STAT_SELFTEST_FAIL (1<<5) /* Self-test diagnostic error flag */
+#define ADIS16203_DIAG_STAT_SPI_FAIL     (1<<3) /* SPI communications failure */
+#define ADIS16203_DIAG_STAT_FLASH_UPT    (1<<2) /* Flash update failure */
+#define ADIS16203_DIAG_STAT_POWER_HIGH   (1<<1) /* Power supply above 3.625 V */
+#define ADIS16203_DIAG_STAT_POWER_LOW    (1<<0) /* Power supply below 3.15 V */
+
+/* GLOB_CMD */
+#define ADIS16203_GLOB_CMD_SW_RESET    (1<<7)
+#define ADIS16203_GLOB_CMD_CLEAR_STAT  (1<<4)
+#define ADIS16203_GLOB_CMD_FACTORY_CAL (1<<1)
+
+#define ADIS16203_MAX_TX 12
+#define ADIS16203_MAX_RX 10
+
+#define ADIS16203_ERROR_ACTIVE          (1<<14)
+
+/**
+ * struct adis16203_state - device instance specific data
+ * @us:                        actual spi_device
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter:             used to check if new interrupt has been triggered
+ * @last_timestamp:    passing timestamp from th to bh of interrupt handler
+ * @indio_dev:         industrial I/O device structure
+ * @trig:              data ready trigger registered with iio
+ * @tx:                        transmit buffer
+ * @rx:                        recieve buffer
+ * @buf_lock:          mutex to protect tx and rx
+ **/
+struct adis16203_state {
+       struct spi_device               *us;
+       struct work_struct              work_trigger_to_ring;
+       s64                             last_timestamp;
+       struct iio_dev                  *indio_dev;
+       struct iio_trigger              *trig;
+       u8                              *tx;
+       u8                              *rx;
+       struct mutex                    buf_lock;
+};
+
+int adis16203_set_irq(struct device *dev, bool enable);
+
+#ifdef CONFIG_IIO_RING_BUFFER
+enum adis16203_scan {
+       ADIS16203_SCAN_SUPPLY,
+       ADIS16203_SCAN_AUX_ADC,
+       ADIS16203_SCAN_TEMP,
+       ADIS16203_SCAN_INCLI_X,
+       ADIS16203_SCAN_INCLI_Y,
+};
+
+void adis16203_remove_trigger(struct iio_dev *indio_dev);
+int adis16203_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t adis16203_read_data_from_ring(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf);
+
+int adis16203_configure_ring(struct iio_dev *indio_dev);
+void adis16203_unconfigure_ring(struct iio_dev *indio_dev);
+
+int adis16203_initialize_ring(struct iio_ring_buffer *ring);
+void adis16203_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void adis16203_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16203_probe_trigger(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline ssize_t
+adis16203_read_data_from_ring(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       return 0;
+}
+
+static int adis16203_configure_ring(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline void adis16203_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16203_initialize_ring(struct iio_ring_buffer *ring)
+{
+       return 0;
+}
+
+static inline void adis16203_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+
+#endif /* CONFIG_IIO_RING_BUFFER */
+#endif /* SPI_ADIS16203_H_ */
diff --git a/drivers/staging/iio/accel/adis16203_core.c b/drivers/staging/iio/accel/adis16203_core.c
new file mode 100644 (file)
index 0000000..b57f190
--- /dev/null
@@ -0,0 +1,568 @@
+/*
+ * ADIS16203 Programmable Digital Vibration Sensor driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "accel.h"
+#include "inclinometer.h"
+#include "../gyro/gyro.h"
+#include "../adc/adc.h"
+
+#include "adis16203.h"
+
+#define DRIVER_NAME            "adis16203"
+
+static int adis16203_check_status(struct device *dev);
+
+/**
+ * adis16203_spi_write_reg_8() - write single byte to a register
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the register to be written
+ * @val: the value to write
+ **/
+static int adis16203_spi_write_reg_8(struct device *dev,
+               u8 reg_address,
+               u8 val)
+{
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16203_state *st = iio_dev_get_devdata(indio_dev);
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADIS16203_WRITE_REG(reg_address);
+       st->tx[1] = val;
+
+       ret = spi_write(st->us, st->tx, 2);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+/**
+ * adis16203_spi_write_reg_16() - write 2 bytes to a pair of registers
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the lower of the two registers. Second register
+ *               is assumed to have address one greater.
+ * @val: value to be written
+ **/
+static int adis16203_spi_write_reg_16(struct device *dev,
+               u8 lower_reg_address,
+               u16 value)
+{
+       int ret;
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16203_state *st = iio_dev_get_devdata(indio_dev);
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 2,
+                       .cs_change = 1,
+               }, {
+                       .tx_buf = st->tx + 2,
+                       .bits_per_word = 8,
+                       .len = 2,
+                       .cs_change = 1,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADIS16203_WRITE_REG(lower_reg_address);
+       st->tx[1] = value & 0xFF;
+       st->tx[2] = ADIS16203_WRITE_REG(lower_reg_address + 1);
+       st->tx[3] = (value >> 8) & 0xFF;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfers[0], &msg);
+       spi_message_add_tail(&xfers[1], &msg);
+       ret = spi_sync(st->us, &msg);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+/**
+ * adis16203_spi_read_reg_16() - read 2 bytes from a 16-bit register
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the lower of the two registers. Second register
+ *               is assumed to have address one greater.
+ * @val: somewhere to pass back the value read
+ **/
+static int adis16203_spi_read_reg_16(struct device *dev,
+               u8 lower_reg_address,
+               u16 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16203_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 2,
+                       .cs_change = 1,
+                       .delay_usecs = 20,
+               }, {
+                       .rx_buf = st->rx,
+                       .bits_per_word = 8,
+                       .len = 2,
+                       .cs_change = 1,
+                       .delay_usecs = 20,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADIS16203_READ_REG(lower_reg_address);
+       st->tx[1] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfers[0], &msg);
+       spi_message_add_tail(&xfers[1], &msg);
+       ret = spi_sync(st->us, &msg);
+       if (ret) {
+               dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
+                               lower_reg_address);
+               goto error_ret;
+       }
+       *val = (st->rx[0] << 8) | st->rx[1];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static ssize_t adis16203_read_12bit_unsigned(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u16 val = 0;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = adis16203_spi_read_reg_16(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       if (val & ADIS16203_ERROR_ACTIVE)
+               adis16203_check_status(dev);
+
+       return sprintf(buf, "%u\n", val & 0x0FFF);
+}
+
+static ssize_t adis16203_read_temp(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       ssize_t ret;
+       u16 val;
+
+       /* Take the iio_dev status lock */
+       mutex_lock(&indio_dev->mlock);
+
+       ret = adis16203_spi_read_reg_16(dev, ADIS16203_TEMP_OUT, (u16 *)&val);
+       if (ret)
+               goto error_ret;
+
+       if (val & ADIS16203_ERROR_ACTIVE)
+               adis16203_check_status(dev);
+
+       val &= 0xFFF;
+       ret = sprintf(buf, "%d\n", val);
+
+error_ret:
+       mutex_unlock(&indio_dev->mlock);
+       return ret;
+}
+
+static ssize_t adis16203_read_14bit_signed(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       s16 val = 0;
+       ssize_t ret;
+
+       mutex_lock(&indio_dev->mlock);
+
+       ret = adis16203_spi_read_reg_16(dev, this_attr->address, (u16 *)&val);
+       if (!ret) {
+               if (val & ADIS16203_ERROR_ACTIVE)
+                       adis16203_check_status(dev);
+
+               val = ((s16)(val << 2) >> 2);
+               ret = sprintf(buf, "%d\n", val);
+       }
+
+       mutex_unlock(&indio_dev->mlock);
+
+       return ret;
+}
+
+static ssize_t adis16203_write_16bit(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       int ret;
+       long val;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               goto error_ret;
+       ret = adis16203_spi_write_reg_16(dev, this_attr->address, val);
+
+error_ret:
+       return ret ? ret : len;
+}
+
+static int adis16203_reset(struct device *dev)
+{
+       int ret;
+       ret = adis16203_spi_write_reg_8(dev,
+                       ADIS16203_GLOB_CMD,
+                       ADIS16203_GLOB_CMD_SW_RESET);
+       if (ret)
+               dev_err(dev, "problem resetting device");
+
+       return ret;
+}
+
+static ssize_t adis16203_write_reset(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf, size_t len)
+{
+       if (len < 1)
+               return -EINVAL;
+       switch (buf[0]) {
+       case '1':
+       case 'y':
+       case 'Y':
+               return adis16203_reset(dev);
+       }
+       return -EINVAL;
+}
+
+int adis16203_set_irq(struct device *dev, bool enable)
+{
+       int ret = 0;
+       u16 msc;
+
+       ret = adis16203_spi_read_reg_16(dev, ADIS16203_MSC_CTRL, &msc);
+       if (ret)
+               goto error_ret;
+
+       msc |= ADIS16203_MSC_CTRL_ACTIVE_HIGH;
+       msc &= ~ADIS16203_MSC_CTRL_DATA_RDY_DIO1;
+       if (enable)
+               msc |= ADIS16203_MSC_CTRL_DATA_RDY_EN;
+       else
+               msc &= ~ADIS16203_MSC_CTRL_DATA_RDY_EN;
+
+       ret = adis16203_spi_write_reg_16(dev, ADIS16203_MSC_CTRL, msc);
+
+error_ret:
+       return ret;
+}
+
+static int adis16203_check_status(struct device *dev)
+{
+       u16 status;
+       int ret;
+
+       ret = adis16203_spi_read_reg_16(dev, ADIS16203_DIAG_STAT, &status);
+       if (ret < 0) {
+               dev_err(dev, "Reading status failed\n");
+               goto error_ret;
+       }
+       ret = status & 0x1F;
+
+       if (status & ADIS16203_DIAG_STAT_SELFTEST_FAIL)
+               dev_err(dev, "Self test failure\n");
+       if (status & ADIS16203_DIAG_STAT_SPI_FAIL)
+               dev_err(dev, "SPI failure\n");
+       if (status & ADIS16203_DIAG_STAT_FLASH_UPT)
+               dev_err(dev, "Flash update failed\n");
+       if (status & ADIS16203_DIAG_STAT_POWER_HIGH)
+               dev_err(dev, "Power supply above 3.625V\n");
+       if (status & ADIS16203_DIAG_STAT_POWER_LOW)
+               dev_err(dev, "Power supply below 3.15V\n");
+
+error_ret:
+       return ret;
+}
+
+static int adis16203_self_test(struct device *dev)
+{
+       int ret;
+       ret = adis16203_spi_write_reg_16(dev,
+                       ADIS16203_MSC_CTRL,
+                       ADIS16203_MSC_CTRL_SELF_TEST_EN);
+       if (ret) {
+               dev_err(dev, "problem starting self test");
+               goto err_ret;
+       }
+
+       adis16203_check_status(dev);
+
+err_ret:
+       return ret;
+}
+
+static int adis16203_initial_setup(struct adis16203_state *st)
+{
+       int ret;
+       struct device *dev = &st->indio_dev->dev;
+
+       /* Disable IRQ */
+       ret = adis16203_set_irq(dev, false);
+       if (ret) {
+               dev_err(dev, "disable irq failed");
+               goto err_ret;
+       }
+
+       /* Do self test */
+       ret = adis16203_self_test(dev);
+       if (ret) {
+               dev_err(dev, "self test failure");
+               goto err_ret;
+       }
+
+       /* Read status register to check the result */
+       ret = adis16203_check_status(dev);
+       if (ret) {
+               adis16203_reset(dev);
+               dev_err(dev, "device not playing ball -> reset");
+               msleep(ADIS16203_STARTUP_DELAY);
+               ret = adis16203_check_status(dev);
+               if (ret) {
+                       dev_err(dev, "giving up");
+                       goto err_ret;
+               }
+       }
+
+       printk(KERN_INFO DRIVER_NAME ": at CS%d (irq %d)\n",
+                       st->us->chip_select, st->us->irq);
+
+err_ret:
+       return ret;
+}
+
+static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16203_read_12bit_unsigned,
+               ADIS16203_SUPPLY_OUT);
+static IIO_CONST_ATTR(in0_supply_scale, "0.00122");
+static IIO_DEV_ATTR_IN_RAW(1, adis16203_read_12bit_unsigned,
+               ADIS16203_AUX_ADC);
+static IIO_CONST_ATTR(in1_scale, "0.00061");
+
+static IIO_DEV_ATTR_INCLI_X(adis16203_read_14bit_signed,
+               ADIS16203_XINCL_OUT);
+static IIO_DEV_ATTR_INCLI_Y(adis16203_read_14bit_signed,
+               ADIS16203_YINCL_OUT);
+static IIO_DEV_ATTR_INCLI_X_OFFSET(S_IWUSR | S_IRUGO,
+               adis16203_read_14bit_signed,
+               adis16203_write_16bit,
+               ADIS16203_INCL_NULL);
+static IIO_CONST_ATTR(incli_scale, "0.025");
+
+static IIO_DEV_ATTR_TEMP_RAW(adis16203_read_temp);
+static IIO_CONST_ATTR(temp_offset, "25");
+static IIO_CONST_ATTR(temp_scale, "-0.47");
+
+static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16203_write_reset, 0);
+
+static IIO_CONST_ATTR(name, "adis16203");
+
+static struct attribute *adis16203_event_attributes[] = {
+       NULL
+};
+
+static struct attribute_group adis16203_event_attribute_group = {
+       .attrs = adis16203_event_attributes,
+};
+
+static struct attribute *adis16203_attributes[] = {
+       &iio_dev_attr_in0_supply_raw.dev_attr.attr,
+       &iio_const_attr_in0_supply_scale.dev_attr.attr,
+       &iio_dev_attr_temp_raw.dev_attr.attr,
+       &iio_const_attr_temp_offset.dev_attr.attr,
+       &iio_const_attr_temp_scale.dev_attr.attr,
+       &iio_dev_attr_reset.dev_attr.attr,
+       &iio_const_attr_name.dev_attr.attr,
+       &iio_dev_attr_in1_raw.dev_attr.attr,
+       &iio_const_attr_in1_scale.dev_attr.attr,
+       &iio_dev_attr_incli_x_raw.dev_attr.attr,
+       &iio_dev_attr_incli_y_raw.dev_attr.attr,
+       &iio_dev_attr_incli_x_offset.dev_attr.attr,
+       &iio_const_attr_incli_scale.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group adis16203_attribute_group = {
+       .attrs = adis16203_attributes,
+};
+
+static int __devinit adis16203_probe(struct spi_device *spi)
+{
+       int ret, regdone = 0;
+       struct adis16203_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+       if (!st) {
+               ret =  -ENOMEM;
+               goto error_ret;
+       }
+       /* this is only used for removal purposes */
+       spi_set_drvdata(spi, st);
+
+       /* Allocate the comms buffers */
+       st->rx = kzalloc(sizeof(*st->rx)*ADIS16203_MAX_RX, GFP_KERNEL);
+       if (st->rx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->tx = kzalloc(sizeof(*st->tx)*ADIS16203_MAX_TX, GFP_KERNEL);
+       if (st->tx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_rx;
+       }
+       st->us = spi;
+       mutex_init(&st->buf_lock);
+       /* setup the industrialio driver allocated elements */
+       st->indio_dev = iio_allocate_device();
+       if (st->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_tx;
+       }
+
+       st->indio_dev->dev.parent = &spi->dev;
+       st->indio_dev->num_interrupt_lines = 1;
+       st->indio_dev->event_attrs = &adis16203_event_attribute_group;
+       st->indio_dev->attrs = &adis16203_attribute_group;
+       st->indio_dev->dev_data = (void *)(st);
+       st->indio_dev->driver_module = THIS_MODULE;
+       st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = adis16203_configure_ring(st->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       ret = iio_device_register(st->indio_dev);
+       if (ret)
+               goto error_unreg_ring_funcs;
+       regdone = 1;
+
+       ret = adis16203_initialize_ring(st->indio_dev->ring);
+       if (ret) {
+               printk(KERN_ERR "failed to initialize the ring\n");
+               goto error_unreg_ring_funcs;
+       }
+
+       if (spi->irq) {
+               ret = iio_register_interrupt_line(spi->irq,
+                               st->indio_dev,
+                               0,
+                               IRQF_TRIGGER_RISING,
+                               "adis16203");
+               if (ret)
+                       goto error_uninitialize_ring;
+
+               ret = adis16203_probe_trigger(st->indio_dev);
+               if (ret)
+                       goto error_unregister_line;
+       }
+
+       /* Get the device into a sane initial state */
+       ret = adis16203_initial_setup(st);
+       if (ret)
+               goto error_remove_trigger;
+       return 0;
+
+error_remove_trigger:
+       adis16203_remove_trigger(st->indio_dev);
+error_unregister_line:
+       if (spi->irq)
+               iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+       adis16203_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+       adis16203_unconfigure_ring(st->indio_dev);
+error_free_dev:
+       if (regdone)
+               iio_device_unregister(st->indio_dev);
+       else
+               iio_free_device(st->indio_dev);
+error_free_tx:
+       kfree(st->tx);
+error_free_rx:
+       kfree(st->rx);
+error_free_st:
+       kfree(st);
+error_ret:
+       return ret;
+}
+
+static int adis16203_remove(struct spi_device *spi)
+{
+       struct adis16203_state *st = spi_get_drvdata(spi);
+       struct iio_dev *indio_dev = st->indio_dev;
+
+       flush_scheduled_work();
+
+       adis16203_remove_trigger(indio_dev);
+       if (spi->irq)
+               iio_unregister_interrupt_line(indio_dev, 0);
+
+       adis16203_uninitialize_ring(indio_dev->ring);
+       iio_device_unregister(indio_dev);
+       adis16203_unconfigure_ring(indio_dev);
+       kfree(st->tx);
+       kfree(st->rx);
+       kfree(st);
+
+       return 0;
+}
+
+static struct spi_driver adis16203_driver = {
+       .driver = {
+               .name = "adis16203",
+               .owner = THIS_MODULE,
+       },
+       .probe = adis16203_probe,
+       .remove = __devexit_p(adis16203_remove),
+};
+
+static __init int adis16203_init(void)
+{
+       return spi_register_driver(&adis16203_driver);
+}
+module_init(adis16203_init);
+
+static __exit void adis16203_exit(void)
+{
+       spi_unregister_driver(&adis16203_driver);
+}
+module_exit(adis16203_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADIS16203 Programmable Digital Vibration Sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/accel/adis16203_ring.c b/drivers/staging/iio/accel/adis16203_ring.c
new file mode 100644 (file)
index 0000000..3d774f7
--- /dev/null
@@ -0,0 +1,211 @@
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../ring_sw.h"
+#include "accel.h"
+#include "../trigger.h"
+#include "adis16203.h"
+
+static IIO_SCAN_EL_C(in_supply, ADIS16203_SCAN_SUPPLY, ADIS16203_SUPPLY_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(in_supply, u, 12, 16);
+static IIO_SCAN_EL_C(in0, ADIS16203_SCAN_AUX_ADC, ADIS16203_AUX_ADC, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(in0, u, 12, 16);
+static IIO_SCAN_EL_C(temp, ADIS16203_SCAN_TEMP, ADIS16203_TEMP_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(temp, u, 12, 16);
+static IIO_SCAN_EL_C(incli_x, ADIS16203_SCAN_INCLI_X,
+                    ADIS16203_XINCL_OUT, NULL);
+static IIO_SCAN_EL_C(incli_y, ADIS16203_SCAN_INCLI_Y,
+                    ADIS16203_YINCL_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(incli, s, 14, 16);
+static IIO_SCAN_EL_TIMESTAMP(5);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64);
+
+static struct attribute *adis16203_scan_el_attrs[] = {
+       &iio_scan_el_in_supply.dev_attr.attr,
+       &iio_const_attr_in_supply_index.dev_attr.attr,
+       &iio_const_attr_in_supply_type.dev_attr.attr,
+       &iio_scan_el_in0.dev_attr.attr,
+       &iio_const_attr_in0_index.dev_attr.attr,
+       &iio_const_attr_in0_type.dev_attr.attr,
+       &iio_scan_el_temp.dev_attr.attr,
+       &iio_const_attr_temp_index.dev_attr.attr,
+       &iio_const_attr_temp_type.dev_attr.attr,
+       &iio_scan_el_incli_x.dev_attr.attr,
+       &iio_const_attr_incli_x_index.dev_attr.attr,
+       &iio_scan_el_incli_y.dev_attr.attr,
+       &iio_const_attr_incli_y_index.dev_attr.attr,
+       &iio_const_attr_incli_type.dev_attr.attr,
+       &iio_scan_el_timestamp.dev_attr.attr,
+       &iio_const_attr_timestamp_index.dev_attr.attr,
+       &iio_const_attr_timestamp_type.dev_attr.attr,
+       NULL,
+};
+
+static struct attribute_group adis16203_scan_el_group = {
+       .attrs = adis16203_scan_el_attrs,
+       .name = "scan_elements",
+};
+
+/**
+ * adis16203_poll_func_th() top half interrupt handler called by trigger
+ * @private_data:      iio_dev
+ **/
+static void adis16203_poll_func_th(struct iio_dev *indio_dev, s64 timestamp)
+{
+       struct adis16203_state *st = iio_dev_get_devdata(indio_dev);
+       st->last_timestamp = timestamp;
+       schedule_work(&st->work_trigger_to_ring);
+}
+
+/**
+ * adis16203_read_ring_data() read data registers which will be placed into ring
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @rx: somewhere to pass back the value read
+ **/
+static int adis16203_read_ring_data(struct device *dev, u8 *rx)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16203_state *st = iio_dev_get_devdata(indio_dev);
+       struct spi_transfer xfers[ADIS16203_OUTPUTS + 1];
+       int ret;
+       int i;
+
+       mutex_lock(&st->buf_lock);
+
+       spi_message_init(&msg);
+
+       memset(xfers, 0, sizeof(xfers));
+       for (i = 0; i <= ADIS16203_OUTPUTS; i++) {
+               xfers[i].bits_per_word = 8;
+               xfers[i].cs_change = 1;
+               xfers[i].len = 2;
+               xfers[i].delay_usecs = 20;
+               xfers[i].tx_buf = st->tx + 2 * i;
+               if (i < 1) /* SUPPLY_OUT: 0x02, AUX_ADC: 0x08 */
+                       st->tx[2 * i] = ADIS16203_READ_REG(ADIS16203_SUPPLY_OUT + 2 * i);
+               else
+                       st->tx[2 * i] = ADIS16203_READ_REG(ADIS16203_SUPPLY_OUT + 2 * i + 6);
+               st->tx[2 * i + 1] = 0;
+               if (i >= 1)
+                       xfers[i].rx_buf = rx + 2 * (i - 1);
+               spi_message_add_tail(&xfers[i], &msg);
+       }
+
+       ret = spi_sync(st->us, &msg);
+       if (ret)
+               dev_err(&st->us->dev, "problem when burst reading");
+
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
+ * specific to be rolled into the core.
+ */
+static void adis16203_trigger_bh_to_ring(struct work_struct *work_s)
+{
+       struct adis16203_state *st
+               = container_of(work_s, struct adis16203_state,
+                              work_trigger_to_ring);
+       struct iio_ring_buffer *ring = st->indio_dev->ring;
+
+       int i = 0;
+       s16 *data;
+       size_t datasize = ring->access.get_bytes_per_datum(ring);
+
+       data = kmalloc(datasize, GFP_KERNEL);
+       if (data == NULL) {
+               dev_err(&st->us->dev, "memory alloc failed in ring bh");
+               return;
+       }
+
+       if (ring->scan_count)
+               if (adis16203_read_ring_data(&st->indio_dev->dev, st->rx) >= 0)
+                       for (; i < ring->scan_count; i++)
+                               data[i] = be16_to_cpup(
+                                       (__be16 *)&(st->rx[i*2]));
+
+       /* Guaranteed to be aligned with 8 byte boundary */
+       if (ring->scan_timestamp)
+               *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp;
+
+       ring->access.store_to(ring,
+                             (u8 *)data,
+                             st->last_timestamp);
+
+       iio_trigger_notify_done(st->indio_dev->trig);
+       kfree(data);
+
+       return;
+}
+
+void adis16203_unconfigure_ring(struct iio_dev *indio_dev)
+{
+       kfree(indio_dev->pollfunc);
+       iio_sw_rb_free(indio_dev->ring);
+}
+
+int adis16203_configure_ring(struct iio_dev *indio_dev)
+{
+       int ret = 0;
+       struct adis16203_state *st = indio_dev->dev_data;
+       struct iio_ring_buffer *ring;
+       INIT_WORK(&st->work_trigger_to_ring, adis16203_trigger_bh_to_ring);
+
+       ring = iio_sw_rb_allocate(indio_dev);
+       if (!ring) {
+               ret = -ENOMEM;
+               return ret;
+       }
+       indio_dev->ring = ring;
+       /* Effectively select the ring buffer implementation */
+       iio_ring_sw_register_funcs(&ring->access);
+       ring->bpe = 2;
+       ring->scan_el_attrs = &adis16203_scan_el_group;
+       ring->scan_timestamp = true;
+       ring->preenable = &iio_sw_ring_preenable;
+       ring->postenable = &iio_triggered_ring_postenable;
+       ring->predisable = &iio_triggered_ring_predisable;
+       ring->owner = THIS_MODULE;
+
+       /* Set default scan mode */
+       iio_scan_mask_set(ring, iio_scan_el_in_supply.number);
+       iio_scan_mask_set(ring, iio_scan_el_temp.number);
+       iio_scan_mask_set(ring, iio_scan_el_in0.number);
+       iio_scan_mask_set(ring, iio_scan_el_incli_x.number);
+       iio_scan_mask_set(ring, iio_scan_el_incli_y.number);
+
+       ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16203_poll_func_th);
+       if (ret)
+               goto error_iio_sw_rb_free;
+
+       indio_dev->modes |= INDIO_RING_TRIGGERED;
+       return 0;
+
+error_iio_sw_rb_free:
+       iio_sw_rb_free(indio_dev->ring);
+       return ret;
+}
+
+int adis16203_initialize_ring(struct iio_ring_buffer *ring)
+{
+       return iio_ring_buffer_register(ring, 0);
+}
+
+void adis16203_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+       iio_ring_buffer_unregister(ring);
+}
diff --git a/drivers/staging/iio/accel/adis16203_trigger.c b/drivers/staging/iio/accel/adis16203_trigger.c
new file mode 100644 (file)
index 0000000..50be51c
--- /dev/null
@@ -0,0 +1,122 @@
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../trigger.h"
+#include "adis16203.h"
+
+/**
+ * adis16203_data_rdy_trig_poll() the event handler for the data rdy trig
+ **/
+static int adis16203_data_rdy_trig_poll(struct iio_dev *dev_info,
+                                      int index,
+                                      s64 timestamp,
+                                      int no_test)
+{
+       struct adis16203_state *st = iio_dev_get_devdata(dev_info);
+       struct iio_trigger *trig = st->trig;
+
+       iio_trigger_poll(trig, timestamp);
+
+       return IRQ_HANDLED;
+}
+
+IIO_EVENT_SH(data_rdy_trig, &adis16203_data_rdy_trig_poll);
+
+static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL);
+
+static struct attribute *adis16203_trigger_attrs[] = {
+       &dev_attr_name.attr,
+       NULL,
+};
+
+static const struct attribute_group adis16203_trigger_attr_group = {
+       .attrs = adis16203_trigger_attrs,
+};
+
+/**
+ * adis16203_data_rdy_trigger_set_state() set datardy interrupt state
+ **/
+static int adis16203_data_rdy_trigger_set_state(struct iio_trigger *trig,
+                                               bool state)
+{
+       struct adis16203_state *st = trig->private_data;
+       struct iio_dev *indio_dev = st->indio_dev;
+       int ret = 0;
+
+       dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state);
+       ret = adis16203_set_irq(&st->indio_dev->dev, state);
+       if (state == false) {
+               iio_remove_event_from_list(&iio_event_data_rdy_trig,
+                                          &indio_dev->interrupts[0]
+                                          ->ev_list);
+               flush_scheduled_work();
+       } else {
+               iio_add_event_to_list(&iio_event_data_rdy_trig,
+                                     &indio_dev->interrupts[0]->ev_list);
+       }
+       return ret;
+}
+
+/**
+ * adis16203_trig_try_reen() try renabling irq for data rdy trigger
+ * @trig:      the datardy trigger
+ **/
+static int adis16203_trig_try_reen(struct iio_trigger *trig)
+{
+       struct adis16203_state *st = trig->private_data;
+       enable_irq(st->us->irq);
+       return 0;
+}
+
+int adis16203_probe_trigger(struct iio_dev *indio_dev)
+{
+       int ret;
+       struct adis16203_state *st = indio_dev->dev_data;
+
+       st->trig = iio_allocate_trigger();
+       st->trig->name = kasprintf(GFP_KERNEL,
+                               "adis16203-dev%d",
+                               indio_dev->id);
+       if (!st->trig->name) {
+               ret = -ENOMEM;
+               goto error_free_trig;
+       }
+       st->trig->dev.parent = &st->us->dev;
+       st->trig->owner = THIS_MODULE;
+       st->trig->private_data = st;
+       st->trig->set_trigger_state = &adis16203_data_rdy_trigger_set_state;
+       st->trig->try_reenable = &adis16203_trig_try_reen;
+       st->trig->control_attrs = &adis16203_trigger_attr_group;
+       ret = iio_trigger_register(st->trig);
+
+       /* select default trigger */
+       indio_dev->trig = st->trig;
+       if (ret)
+               goto error_free_trig_name;
+
+       return 0;
+
+error_free_trig_name:
+       kfree(st->trig->name);
+error_free_trig:
+       iio_free_trigger(st->trig);
+
+       return ret;
+}
+
+void adis16203_remove_trigger(struct iio_dev *indio_dev)
+{
+       struct adis16203_state *state = indio_dev->dev_data;
+
+       iio_trigger_unregister(state->trig);
+       kfree(state->trig->name);
+       iio_free_trigger(state->trig);
+}
diff --git a/drivers/staging/iio/accel/adis16204.h b/drivers/staging/iio/accel/adis16204.h
new file mode 100644 (file)
index 0000000..e9ed7cb
--- /dev/null
@@ -0,0 +1,151 @@
+#ifndef SPI_ADIS16204_H_
+#define SPI_ADIS16204_H_
+
+#define ADIS16204_STARTUP_DELAY        220 /* ms */
+
+#define ADIS16204_READ_REG(a)    a
+#define ADIS16204_WRITE_REG(a) ((a) | 0x80)
+
+#define ADIS16204_FLASH_CNT      0x00 /* Flash memory write count */
+#define ADIS16204_SUPPLY_OUT     0x02 /* Output, power supply */
+#define ADIS16204_XACCL_OUT      0x04 /* Output, x-axis accelerometer */
+#define ADIS16204_YACCL_OUT      0x06 /* Output, y-axis accelerometer */
+#define ADIS16204_AUX_ADC        0x08 /* Output, auxiliary ADC input */
+#define ADIS16204_TEMP_OUT       0x0A /* Output, temperature */
+#define ADIS16204_X_PEAK_OUT     0x0C /* Twos complement */
+#define ADIS16204_Y_PEAK_OUT     0x0E /* Twos complement */
+#define ADIS16204_XACCL_NULL     0x10 /* Calibration, x-axis acceleration offset null */
+#define ADIS16204_YACCL_NULL     0x12 /* Calibration, y-axis acceleration offset null */
+#define ADIS16204_XACCL_SCALE    0x14 /* X-axis scale factor calibration register */
+#define ADIS16204_YACCL_SCALE    0x16 /* Y-axis scale factor calibration register */
+#define ADIS16204_XY_RSS_OUT     0x18 /* XY combined acceleration (RSS) */
+#define ADIS16204_XY_PEAK_OUT    0x1A /* Peak, XY combined output (RSS) */
+#define ADIS16204_CAP_BUF_1      0x1C /* Capture buffer output register 1 */
+#define ADIS16204_CAP_BUF_2      0x1E /* Capture buffer output register 2 */
+#define ADIS16204_ALM_MAG1       0x20 /* Alarm 1 amplitude threshold */
+#define ADIS16204_ALM_MAG2       0x22 /* Alarm 2 amplitude threshold */
+#define ADIS16204_ALM_CTRL       0x28 /* Alarm control */
+#define ADIS16204_CAPT_PNTR      0x2A /* Capture register address pointer */
+#define ADIS16204_AUX_DAC        0x30 /* Auxiliary DAC data */
+#define ADIS16204_GPIO_CTRL      0x32 /* General-purpose digital input/output control */
+#define ADIS16204_MSC_CTRL       0x34 /* Miscellaneous control */
+#define ADIS16204_SMPL_PRD       0x36 /* Internal sample period (rate) control */
+#define ADIS16204_AVG_CNT        0x38 /* Operation, filter configuration */
+#define ADIS16204_SLP_CNT        0x3A /* Operation, sleep mode control */
+#define ADIS16204_DIAG_STAT      0x3C /* Diagnostics, system status register */
+#define ADIS16204_GLOB_CMD       0x3E /* Operation, system command register */
+
+#define ADIS16204_OUTPUTS        5
+
+/* MSC_CTRL */
+#define ADIS16204_MSC_CTRL_PWRUP_SELF_TEST     (1 << 10) /* Self-test at power-on: 1 = disabled, 0 = enabled */
+#define ADIS16204_MSC_CTRL_SELF_TEST_EN                (1 << 8)  /* Self-test enable */
+#define ADIS16204_MSC_CTRL_DATA_RDY_EN         (1 << 2)  /* Data-ready enable: 1 = enabled, 0 = disabled */
+#define ADIS16204_MSC_CTRL_ACTIVE_HIGH         (1 << 1)  /* Data-ready polarity: 1 = active high, 0 = active low */
+#define ADIS16204_MSC_CTRL_DATA_RDY_DIO2       (1 << 0)  /* Data-ready line selection: 1 = DIO2, 0 = DIO1 */
+
+/* DIAG_STAT */
+#define ADIS16204_DIAG_STAT_ALARM2        (1<<9) /* Alarm 2 status: 1 = alarm active, 0 = alarm inactive */
+#define ADIS16204_DIAG_STAT_ALARM1        (1<<8) /* Alarm 1 status: 1 = alarm active, 0 = alarm inactive */
+#define ADIS16204_DIAG_STAT_SELFTEST_FAIL (1<<5) /* Self-test diagnostic error flag: 1 = error condition,
+                                               0 = normal operation */
+#define ADIS16204_DIAG_STAT_SPI_FAIL     (1<<3) /* SPI communications failure */
+#define ADIS16204_DIAG_STAT_FLASH_UPT    (1<<2) /* Flash update failure */
+#define ADIS16204_DIAG_STAT_POWER_HIGH   (1<<1) /* Power supply above 3.625 V */
+#define ADIS16204_DIAG_STAT_POWER_LOW    (1<<0) /* Power supply below 2.975 V */
+
+/* GLOB_CMD */
+#define ADIS16204_GLOB_CMD_SW_RESET    (1<<7)
+#define ADIS16204_GLOB_CMD_CLEAR_STAT  (1<<4)
+#define ADIS16204_GLOB_CMD_FACTORY_CAL (1<<1)
+
+#define ADIS16204_MAX_TX 24
+#define ADIS16204_MAX_RX 24
+
+#define ADIS16204_ERROR_ACTIVE          (1<<14)
+
+/**
+ * struct adis16204_state - device instance specific data
+ * @us:                        actual spi_device
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter:             used to check if new interrupt has been triggered
+ * @last_timestamp:    passing timestamp from th to bh of interrupt handler
+ * @indio_dev:         industrial I/O device structure
+ * @trig:              data ready trigger registered with iio
+ * @tx:                        transmit buffer
+ * @rx:                        recieve buffer
+ * @buf_lock:          mutex to protect tx and rx
+ **/
+struct adis16204_state {
+       struct spi_device               *us;
+       struct work_struct              work_trigger_to_ring;
+       s64                             last_timestamp;
+       struct iio_dev                  *indio_dev;
+       struct iio_trigger              *trig;
+       u8                              *tx;
+       u8                              *rx;
+       struct mutex                    buf_lock;
+};
+
+int adis16204_set_irq(struct device *dev, bool enable);
+
+#ifdef CONFIG_IIO_RING_BUFFER
+enum adis16204_scan {
+       ADIS16204_SCAN_SUPPLY,
+       ADIS16204_SCAN_ACC_X,
+       ADIS16204_SCAN_ACC_Y,
+       ADIS16204_SCAN_AUX_ADC,
+       ADIS16204_SCAN_TEMP,
+};
+
+void adis16204_remove_trigger(struct iio_dev *indio_dev);
+int adis16204_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t adis16204_read_data_from_ring(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf);
+
+int adis16204_configure_ring(struct iio_dev *indio_dev);
+void adis16204_unconfigure_ring(struct iio_dev *indio_dev);
+
+int adis16204_initialize_ring(struct iio_ring_buffer *ring);
+void adis16204_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void adis16204_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16204_probe_trigger(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline ssize_t
+adis16204_read_data_from_ring(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       return 0;
+}
+
+static int adis16204_configure_ring(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline void adis16204_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16204_initialize_ring(struct iio_ring_buffer *ring)
+{
+       return 0;
+}
+
+static inline void adis16204_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+
+#endif /* CONFIG_IIO_RING_BUFFER */
+#endif /* SPI_ADIS16204_H_ */
diff --git a/drivers/staging/iio/accel/adis16204_core.c b/drivers/staging/iio/accel/adis16204_core.c
new file mode 100644 (file)
index 0000000..cc15e40
--- /dev/null
@@ -0,0 +1,613 @@
+/*
+ * ADIS16204 Programmable High-g Digital Impact Sensor and Recorder
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "accel.h"
+#include "../gyro/gyro.h"
+#include "../adc/adc.h"
+
+#include "adis16204.h"
+
+#define DRIVER_NAME            "adis16204"
+
+static int adis16204_check_status(struct device *dev);
+
+/**
+ * adis16204_spi_write_reg_8() - write single byte to a register
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the register to be written
+ * @val: the value to write
+ **/
+static int adis16204_spi_write_reg_8(struct device *dev,
+               u8 reg_address,
+               u8 val)
+{
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16204_state *st = iio_dev_get_devdata(indio_dev);
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADIS16204_WRITE_REG(reg_address);
+       st->tx[1] = val;
+
+       ret = spi_write(st->us, st->tx, 2);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+/**
+ * adis16204_spi_write_reg_16() - write 2 bytes to a pair of registers
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the lower of the two registers. Second register
+ *               is assumed to have address one greater.
+ * @val: value to be written
+ **/
+static int adis16204_spi_write_reg_16(struct device *dev,
+               u8 lower_reg_address,
+               u16 value)
+{
+       int ret;
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16204_state *st = iio_dev_get_devdata(indio_dev);
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 2,
+                       .cs_change = 1,
+               }, {
+                       .tx_buf = st->tx + 2,
+                       .bits_per_word = 8,
+                       .len = 2,
+                       .cs_change = 1,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADIS16204_WRITE_REG(lower_reg_address);
+       st->tx[1] = value & 0xFF;
+       st->tx[2] = ADIS16204_WRITE_REG(lower_reg_address + 1);
+       st->tx[3] = (value >> 8) & 0xFF;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfers[0], &msg);
+       spi_message_add_tail(&xfers[1], &msg);
+       ret = spi_sync(st->us, &msg);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+/**
+ * adis16204_spi_read_reg_16() - read 2 bytes from a 16-bit register
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the lower of the two registers. Second register
+ *               is assumed to have address one greater.
+ * @val: somewhere to pass back the value read
+ **/
+static int adis16204_spi_read_reg_16(struct device *dev,
+               u8 lower_reg_address,
+               u16 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16204_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 2,
+                       .cs_change = 1,
+                       .delay_usecs = 20,
+               }, {
+                       .rx_buf = st->rx,
+                       .bits_per_word = 8,
+                       .len = 2,
+                       .cs_change = 1,
+                       .delay_usecs = 20,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADIS16204_READ_REG(lower_reg_address);
+       st->tx[1] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfers[0], &msg);
+       spi_message_add_tail(&xfers[1], &msg);
+       ret = spi_sync(st->us, &msg);
+       if (ret) {
+               dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
+                               lower_reg_address);
+               goto error_ret;
+       }
+       *val = (st->rx[0] << 8) | st->rx[1];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static ssize_t adis16204_read_12bit_unsigned(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u16 val = 0;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = adis16204_spi_read_reg_16(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       if (val & ADIS16204_ERROR_ACTIVE)
+               adis16204_check_status(dev);
+
+       return sprintf(buf, "%u\n", val & 0x0FFF);
+}
+
+static ssize_t adis16204_read_temp(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       ssize_t ret;
+       u16 val;
+
+       /* Take the iio_dev status lock */
+       mutex_lock(&indio_dev->mlock);
+
+       ret = adis16204_spi_read_reg_16(dev, ADIS16204_TEMP_OUT, (u16 *)&val);
+       if (ret)
+               goto error_ret;
+
+       if (val & ADIS16204_ERROR_ACTIVE)
+               adis16204_check_status(dev);
+
+       val &= 0xFFF;
+       ret = sprintf(buf, "%d\n", val);
+
+error_ret:
+       mutex_unlock(&indio_dev->mlock);
+       return ret;
+}
+
+static ssize_t adis16204_read_12bit_signed(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       s16 val = 0;
+       ssize_t ret;
+
+       mutex_lock(&indio_dev->mlock);
+
+       ret = adis16204_spi_read_reg_16(dev, this_attr->address, (u16 *)&val);
+       if (!ret) {
+               if (val & ADIS16204_ERROR_ACTIVE)
+                       adis16204_check_status(dev);
+
+               val = ((s16)(val << 4) >> 4);
+               ret = sprintf(buf, "%d\n", val);
+       }
+
+       mutex_unlock(&indio_dev->mlock);
+
+       return ret;
+}
+
+static ssize_t adis16204_read_14bit_signed(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       s16 val = 0;
+       ssize_t ret;
+
+       mutex_lock(&indio_dev->mlock);
+
+       ret = adis16204_spi_read_reg_16(dev, this_attr->address, (u16 *)&val);
+       if (!ret) {
+               if (val & ADIS16204_ERROR_ACTIVE)
+                       adis16204_check_status(dev);
+
+               val = ((s16)(val << 2) >> 2);
+               ret = sprintf(buf, "%d\n", val);
+       }
+
+       mutex_unlock(&indio_dev->mlock);
+
+       return ret;
+}
+
+static ssize_t adis16204_write_16bit(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       int ret;
+       long val;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               goto error_ret;
+       ret = adis16204_spi_write_reg_16(dev, this_attr->address, val);
+
+error_ret:
+       return ret ? ret : len;
+}
+
+static int adis16204_reset(struct device *dev)
+{
+       int ret;
+       ret = adis16204_spi_write_reg_8(dev,
+                       ADIS16204_GLOB_CMD,
+                       ADIS16204_GLOB_CMD_SW_RESET);
+       if (ret)
+               dev_err(dev, "problem resetting device");
+
+       return ret;
+}
+
+static ssize_t adis16204_write_reset(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf, size_t len)
+{
+       if (len < 1)
+               return -EINVAL;
+       switch (buf[0]) {
+       case '1':
+       case 'y':
+       case 'Y':
+               return adis16204_reset(dev);
+       }
+       return -EINVAL;
+}
+
+int adis16204_set_irq(struct device *dev, bool enable)
+{
+       int ret = 0;
+       u16 msc;
+
+       ret = adis16204_spi_read_reg_16(dev, ADIS16204_MSC_CTRL, &msc);
+       if (ret)
+               goto error_ret;
+
+       msc |= ADIS16204_MSC_CTRL_ACTIVE_HIGH;
+       msc &= ~ADIS16204_MSC_CTRL_DATA_RDY_DIO2;
+       if (enable)
+               msc |= ADIS16204_MSC_CTRL_DATA_RDY_EN;
+       else
+               msc &= ~ADIS16204_MSC_CTRL_DATA_RDY_EN;
+
+       ret = adis16204_spi_write_reg_16(dev, ADIS16204_MSC_CTRL, msc);
+
+error_ret:
+       return ret;
+}
+
+static int adis16204_check_status(struct device *dev)
+{
+       u16 status;
+       int ret;
+
+       ret = adis16204_spi_read_reg_16(dev, ADIS16204_DIAG_STAT, &status);
+       if (ret < 0) {
+               dev_err(dev, "Reading status failed\n");
+               goto error_ret;
+       }
+       ret = status & 0x1F;
+
+       if (status & ADIS16204_DIAG_STAT_SELFTEST_FAIL)
+               dev_err(dev, "Self test failure\n");
+       if (status & ADIS16204_DIAG_STAT_SPI_FAIL)
+               dev_err(dev, "SPI failure\n");
+       if (status & ADIS16204_DIAG_STAT_FLASH_UPT)
+               dev_err(dev, "Flash update failed\n");
+       if (status & ADIS16204_DIAG_STAT_POWER_HIGH)
+               dev_err(dev, "Power supply above 3.625V\n");
+       if (status & ADIS16204_DIAG_STAT_POWER_LOW)
+               dev_err(dev, "Power supply below 2.975V\n");
+
+error_ret:
+       return ret;
+}
+
+static int adis16204_self_test(struct device *dev)
+{
+       int ret;
+       ret = adis16204_spi_write_reg_16(dev,
+                       ADIS16204_MSC_CTRL,
+                       ADIS16204_MSC_CTRL_SELF_TEST_EN);
+       if (ret) {
+               dev_err(dev, "problem starting self test");
+               goto err_ret;
+       }
+
+       adis16204_check_status(dev);
+
+err_ret:
+       return ret;
+}
+
+static int adis16204_initial_setup(struct adis16204_state *st)
+{
+       int ret;
+       struct device *dev = &st->indio_dev->dev;
+
+       /* Disable IRQ */
+       ret = adis16204_set_irq(dev, false);
+       if (ret) {
+               dev_err(dev, "disable irq failed");
+               goto err_ret;
+       }
+
+       /* Do self test */
+       ret = adis16204_self_test(dev);
+       if (ret) {
+               dev_err(dev, "self test failure");
+               goto err_ret;
+       }
+
+       /* Read status register to check the result */
+       ret = adis16204_check_status(dev);
+       if (ret) {
+               adis16204_reset(dev);
+               dev_err(dev, "device not playing ball -> reset");
+               msleep(ADIS16204_STARTUP_DELAY);
+               ret = adis16204_check_status(dev);
+               if (ret) {
+                       dev_err(dev, "giving up");
+                       goto err_ret;
+               }
+       }
+
+       printk(KERN_INFO DRIVER_NAME ": at CS%d (irq %d)\n",
+                       st->us->chip_select, st->us->irq);
+
+err_ret:
+       return ret;
+}
+
+static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16204_read_12bit_unsigned,
+               ADIS16204_SUPPLY_OUT);
+static IIO_CONST_ATTR(in0_supply_scale, "0.00122");
+static IIO_DEV_ATTR_IN_RAW(1, adis16204_read_12bit_unsigned,
+               ADIS16204_AUX_ADC);
+static IIO_CONST_ATTR(in1_scale, "0.00061");
+
+static IIO_DEV_ATTR_ACCEL_X(adis16204_read_14bit_signed,
+               ADIS16204_XACCL_OUT);
+static IIO_DEV_ATTR_ACCEL_Y(adis16204_read_14bit_signed,
+               ADIS16204_YACCL_OUT);
+static IIO_DEV_ATTR_ACCEL_XY(adis16204_read_14bit_signed,
+               ADIS16204_XY_RSS_OUT);
+static IIO_DEV_ATTR_ACCEL_XPEAK(adis16204_read_14bit_signed,
+               ADIS16204_X_PEAK_OUT);
+static IIO_DEV_ATTR_ACCEL_YPEAK(adis16204_read_14bit_signed,
+               ADIS16204_Y_PEAK_OUT);
+static IIO_DEV_ATTR_ACCEL_XYPEAK(adis16204_read_14bit_signed,
+               ADIS16204_XY_PEAK_OUT);
+static IIO_DEV_ATTR_ACCEL_X_OFFSET(S_IWUSR | S_IRUGO,
+               adis16204_read_12bit_signed,
+               adis16204_write_16bit,
+               ADIS16204_XACCL_NULL);
+static IIO_DEV_ATTR_ACCEL_Y_OFFSET(S_IWUSR | S_IRUGO,
+               adis16204_read_12bit_signed,
+               adis16204_write_16bit,
+               ADIS16204_YACCL_NULL);
+static IIO_CONST_ATTR(accel_x_scale, "0.017125");
+static IIO_CONST_ATTR(accel_y_scale, "0.008407");
+static IIO_CONST_ATTR(accel_xy_scale, "0.017125");
+
+static IIO_DEV_ATTR_TEMP_RAW(adis16204_read_temp);
+static IIO_CONST_ATTR(temp_offset, "25");
+static IIO_CONST_ATTR(temp_scale, "-0.47");
+
+static IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, adis16204_write_reset, 0);
+
+static IIO_CONST_ATTR(name, "adis16204");
+
+static struct attribute *adis16204_event_attributes[] = {
+       NULL
+};
+
+static struct attribute_group adis16204_event_attribute_group = {
+       .attrs = adis16204_event_attributes,
+};
+
+static struct attribute *adis16204_attributes[] = {
+       &iio_dev_attr_in0_supply_raw.dev_attr.attr,
+       &iio_const_attr_in0_supply_scale.dev_attr.attr,
+       &iio_dev_attr_temp_raw.dev_attr.attr,
+       &iio_const_attr_temp_offset.dev_attr.attr,
+       &iio_const_attr_temp_scale.dev_attr.attr,
+       &iio_dev_attr_reset.dev_attr.attr,
+       &iio_const_attr_name.dev_attr.attr,
+       &iio_dev_attr_in1_raw.dev_attr.attr,
+       &iio_const_attr_in1_scale.dev_attr.attr,
+       &iio_dev_attr_accel_x_raw.dev_attr.attr,
+       &iio_dev_attr_accel_y_raw.dev_attr.attr,
+       &iio_dev_attr_accel_xy.dev_attr.attr,
+       &iio_dev_attr_accel_xpeak.dev_attr.attr,
+       &iio_dev_attr_accel_ypeak.dev_attr.attr,
+       &iio_dev_attr_accel_xypeak.dev_attr.attr,
+       &iio_dev_attr_accel_x_offset.dev_attr.attr,
+       &iio_dev_attr_accel_y_offset.dev_attr.attr,
+       &iio_const_attr_accel_x_scale.dev_attr.attr,
+       &iio_const_attr_accel_y_scale.dev_attr.attr,
+       &iio_const_attr_accel_xy_scale.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group adis16204_attribute_group = {
+       .attrs = adis16204_attributes,
+};
+
+static int __devinit adis16204_probe(struct spi_device *spi)
+{
+       int ret, regdone = 0;
+       struct adis16204_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+       if (!st) {
+               ret =  -ENOMEM;
+               goto error_ret;
+       }
+       /* this is only used for removal purposes */
+       spi_set_drvdata(spi, st);
+
+       /* Allocate the comms buffers */
+       st->rx = kzalloc(sizeof(*st->rx)*ADIS16204_MAX_RX, GFP_KERNEL);
+       if (st->rx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->tx = kzalloc(sizeof(*st->tx)*ADIS16204_MAX_TX, GFP_KERNEL);
+       if (st->tx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_rx;
+       }
+       st->us = spi;
+       mutex_init(&st->buf_lock);
+       /* setup the industrialio driver allocated elements */
+       st->indio_dev = iio_allocate_device();
+       if (st->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_tx;
+       }
+
+       st->indio_dev->dev.parent = &spi->dev;
+       st->indio_dev->num_interrupt_lines = 1;
+       st->indio_dev->event_attrs = &adis16204_event_attribute_group;
+       st->indio_dev->attrs = &adis16204_attribute_group;
+       st->indio_dev->dev_data = (void *)(st);
+       st->indio_dev->driver_module = THIS_MODULE;
+       st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = adis16204_configure_ring(st->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       ret = iio_device_register(st->indio_dev);
+       if (ret)
+               goto error_unreg_ring_funcs;
+       regdone = 1;
+
+       ret = adis16204_initialize_ring(st->indio_dev->ring);
+       if (ret) {
+               printk(KERN_ERR "failed to initialize the ring\n");
+               goto error_unreg_ring_funcs;
+       }
+
+       if (spi->irq) {
+               ret = iio_register_interrupt_line(spi->irq,
+                               st->indio_dev,
+                               0,
+                               IRQF_TRIGGER_RISING,
+                               "adis16204");
+               if (ret)
+                       goto error_uninitialize_ring;
+
+               ret = adis16204_probe_trigger(st->indio_dev);
+               if (ret)
+                       goto error_unregister_line;
+       }
+
+       /* Get the device into a sane initial state */
+       ret = adis16204_initial_setup(st);
+       if (ret)
+               goto error_remove_trigger;
+       return 0;
+
+error_remove_trigger:
+       adis16204_remove_trigger(st->indio_dev);
+error_unregister_line:
+       if (spi->irq)
+               iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+       adis16204_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+       adis16204_unconfigure_ring(st->indio_dev);
+error_free_dev:
+       if (regdone)
+               iio_device_unregister(st->indio_dev);
+       else
+               iio_free_device(st->indio_dev);
+error_free_tx:
+       kfree(st->tx);
+error_free_rx:
+       kfree(st->rx);
+error_free_st:
+       kfree(st);
+error_ret:
+       return ret;
+}
+
+static int adis16204_remove(struct spi_device *spi)
+{
+       struct adis16204_state *st = spi_get_drvdata(spi);
+       struct iio_dev *indio_dev = st->indio_dev;
+
+       flush_scheduled_work();
+
+       adis16204_remove_trigger(indio_dev);
+       if (spi->irq)
+               iio_unregister_interrupt_line(indio_dev, 0);
+
+       adis16204_uninitialize_ring(indio_dev->ring);
+       iio_device_unregister(indio_dev);
+       adis16204_unconfigure_ring(indio_dev);
+       kfree(st->tx);
+       kfree(st->rx);
+       kfree(st);
+
+       return 0;
+}
+
+static struct spi_driver adis16204_driver = {
+       .driver = {
+               .name = "adis16204",
+               .owner = THIS_MODULE,
+       },
+       .probe = adis16204_probe,
+       .remove = __devexit_p(adis16204_remove),
+};
+
+static __init int adis16204_init(void)
+{
+       return spi_register_driver(&adis16204_driver);
+}
+module_init(adis16204_init);
+
+static __exit void adis16204_exit(void)
+{
+       spi_unregister_driver(&adis16204_driver);
+}
+module_exit(adis16204_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADIS16204 Programmable High-g Digital Impact Sensor and Recorder");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/accel/adis16204_ring.c b/drivers/staging/iio/accel/adis16204_ring.c
new file mode 100644 (file)
index 0000000..420b160
--- /dev/null
@@ -0,0 +1,206 @@
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../ring_sw.h"
+#include "accel.h"
+#include "../trigger.h"
+#include "adis16204.h"
+
+static IIO_SCAN_EL_C(in_supply, ADIS16204_SCAN_SUPPLY, ADIS16204_SUPPLY_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(in_supply, u, 12, 16);
+static IIO_SCAN_EL_C(accel_x, ADIS16204_SCAN_ACC_X, ADIS16204_XACCL_OUT, NULL);
+static IIO_SCAN_EL_C(accel_y, ADIS16204_SCAN_ACC_Y, ADIS16204_YACCL_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(accel, s, 14, 16);
+static IIO_SCAN_EL_C(in0, ADIS16204_SCAN_AUX_ADC, ADIS16204_AUX_ADC, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(in0, u, 12, 16);
+static IIO_SCAN_EL_C(temp, ADIS16204_SCAN_TEMP, ADIS16204_TEMP_OUT, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(temp, u, 12, 16);
+static IIO_SCAN_EL_TIMESTAMP(5);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64);
+
+static struct attribute *adis16204_scan_el_attrs[] = {
+       &iio_scan_el_in_supply.dev_attr.attr,
+       &iio_const_attr_in_supply_index.dev_attr.attr,
+       &iio_const_attr_in_supply_type.dev_attr.attr,
+       &iio_scan_el_accel_x.dev_attr.attr,
+       &iio_const_attr_accel_x_index.dev_attr.attr,
+       &iio_scan_el_accel_y.dev_attr.attr,
+       &iio_const_attr_accel_y_index.dev_attr.attr,
+       &iio_const_attr_accel_type.dev_attr.attr,
+       &iio_scan_el_in0.dev_attr.attr,
+       &iio_const_attr_in0_index.dev_attr.attr,
+       &iio_const_attr_in0_type.dev_attr.attr,
+       &iio_scan_el_temp.dev_attr.attr,
+       &iio_const_attr_temp_index.dev_attr.attr,
+       &iio_const_attr_temp_type.dev_attr.attr,
+       &iio_scan_el_timestamp.dev_attr.attr,
+       &iio_const_attr_timestamp_index.dev_attr.attr,
+       &iio_const_attr_timestamp_type.dev_attr.attr,
+       NULL,
+};
+
+static struct attribute_group adis16204_scan_el_group = {
+       .attrs = adis16204_scan_el_attrs,
+       .name = "scan_elements",
+};
+
+/**
+ * adis16204_poll_func_th() top half interrupt handler called by trigger
+ * @private_data:      iio_dev
+ **/
+static void adis16204_poll_func_th(struct iio_dev *indio_dev, s64 timestamp)
+{
+       struct adis16204_state *st = iio_dev_get_devdata(indio_dev);
+       st->last_timestamp = timestamp;
+       schedule_work(&st->work_trigger_to_ring);
+}
+
+/**
+ * adis16204_read_ring_data() read data registers which will be placed into ring
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @rx: somewhere to pass back the value read
+ **/
+static int adis16204_read_ring_data(struct device *dev, u8 *rx)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16204_state *st = iio_dev_get_devdata(indio_dev);
+       struct spi_transfer xfers[ADIS16204_OUTPUTS + 1];
+       int ret;
+       int i;
+
+       mutex_lock(&st->buf_lock);
+
+       spi_message_init(&msg);
+
+       memset(xfers, 0, sizeof(xfers));
+       for (i = 0; i <= ADIS16204_OUTPUTS; i++) {
+               xfers[i].bits_per_word = 8;
+               xfers[i].cs_change = 1;
+               xfers[i].len = 2;
+               xfers[i].delay_usecs = 20;
+               xfers[i].tx_buf = st->tx + 2 * i;
+               st->tx[2 * i] = ADIS16204_READ_REG(ADIS16204_SUPPLY_OUT + 2 * i);
+               st->tx[2 * i + 1] = 0;
+               if (i >= 1)
+                       xfers[i].rx_buf = rx + 2 * (i - 1);
+               spi_message_add_tail(&xfers[i], &msg);
+       }
+
+       ret = spi_sync(st->us, &msg);
+       if (ret)
+               dev_err(&st->us->dev, "problem when burst reading");
+
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
+ * specific to be rolled into the core.
+ */
+static void adis16204_trigger_bh_to_ring(struct work_struct *work_s)
+{
+       struct adis16204_state *st
+               = container_of(work_s, struct adis16204_state,
+                              work_trigger_to_ring);
+       struct iio_ring_buffer *ring = st->indio_dev->ring;
+
+       int i = 0;
+       s16 *data;
+       size_t datasize = ring->access.get_bytes_per_datum(ring);
+
+       data = kmalloc(datasize, GFP_KERNEL);
+       if (data == NULL) {
+               dev_err(&st->us->dev, "memory alloc failed in ring bh");
+               return;
+       }
+
+       if (ring->scan_count)
+               if (adis16204_read_ring_data(&st->indio_dev->dev, st->rx) >= 0)
+                       for (; i < ring->scan_count; i++)
+                               data[i] = be16_to_cpup(
+                                       (__be16 *)&(st->rx[i*2]));
+
+       /* Guaranteed to be aligned with 8 byte boundary */
+       if (ring->scan_timestamp)
+               *((s64 *)(data + ((i + 3)/4)*4)) = st->last_timestamp;
+
+       ring->access.store_to(ring,
+                             (u8 *)data,
+                             st->last_timestamp);
+
+       iio_trigger_notify_done(st->indio_dev->trig);
+       kfree(data);
+
+       return;
+}
+
+void adis16204_unconfigure_ring(struct iio_dev *indio_dev)
+{
+       kfree(indio_dev->pollfunc);
+       iio_sw_rb_free(indio_dev->ring);
+}
+
+int adis16204_configure_ring(struct iio_dev *indio_dev)
+{
+       int ret = 0;
+       struct adis16204_state *st = indio_dev->dev_data;
+       struct iio_ring_buffer *ring;
+       INIT_WORK(&st->work_trigger_to_ring, adis16204_trigger_bh_to_ring);
+
+       ring = iio_sw_rb_allocate(indio_dev);
+       if (!ring) {
+               ret = -ENOMEM;
+               return ret;
+       }
+       indio_dev->ring = ring;
+       /* Effectively select the ring buffer implementation */
+       iio_ring_sw_register_funcs(&ring->access);
+       ring->bpe = 2;
+       ring->scan_el_attrs = &adis16204_scan_el_group;
+       ring->scan_timestamp = true;
+       ring->preenable = &iio_sw_ring_preenable;
+       ring->postenable = &iio_triggered_ring_postenable;
+       ring->predisable = &iio_triggered_ring_predisable;
+       ring->owner = THIS_MODULE;
+
+       /* Set default scan mode */
+       iio_scan_mask_set(ring, iio_scan_el_in_supply.number);
+       iio_scan_mask_set(ring, iio_scan_el_accel_x.number);
+       iio_scan_mask_set(ring, iio_scan_el_accel_y.number);
+       iio_scan_mask_set(ring, iio_scan_el_temp.number);
+       iio_scan_mask_set(ring, iio_scan_el_in0.number);
+
+       ret = iio_alloc_pollfunc(indio_dev, NULL, &adis16204_poll_func_th);
+       if (ret)
+               goto error_iio_sw_rb_free;
+
+       indio_dev->modes |= INDIO_RING_TRIGGERED;
+       return 0;
+
+error_iio_sw_rb_free:
+       iio_sw_rb_free(indio_dev->ring);
+       return ret;
+}
+
+int adis16204_initialize_ring(struct iio_ring_buffer *ring)
+{
+       return iio_ring_buffer_register(ring, 0);
+}
+
+void adis16204_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+       iio_ring_buffer_unregister(ring);
+}
diff --git a/drivers/staging/iio/accel/adis16204_trigger.c b/drivers/staging/iio/accel/adis16204_trigger.c
new file mode 100644 (file)
index 0000000..8e9db90
--- /dev/null
@@ -0,0 +1,122 @@
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../trigger.h"
+#include "adis16204.h"
+
+/**
+ * adis16204_data_rdy_trig_poll() the event handler for the data rdy trig
+ **/
+static int adis16204_data_rdy_trig_poll(struct iio_dev *dev_info,
+                                      int index,
+                                      s64 timestamp,
+                                      int no_test)
+{
+       struct adis16204_state *st = iio_dev_get_devdata(dev_info);
+       struct iio_trigger *trig = st->trig;
+
+       iio_trigger_poll(trig, timestamp);
+
+       return IRQ_HANDLED;
+}
+
+IIO_EVENT_SH(data_rdy_trig, &adis16204_data_rdy_trig_poll);
+
+static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL);
+
+static struct attribute *adis16204_trigger_attrs[] = {
+       &dev_attr_name.attr,
+       NULL,
+};
+
+static const struct attribute_group adis16204_trigger_attr_group = {
+       .attrs = adis16204_trigger_attrs,
+};
+
+/**
+ * adis16204_data_rdy_trigger_set_state() set datardy interrupt state
+ **/
+static int adis16204_data_rdy_trigger_set_state(struct iio_trigger *trig,
+                                               bool state)
+{
+       struct adis16204_state *st = trig->private_data;
+       struct iio_dev *indio_dev = st->indio_dev;
+       int ret = 0;
+
+       dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state);
+       ret = adis16204_set_irq(&st->indio_dev->dev, state);
+       if (state == false) {
+               iio_remove_event_from_list(&iio_event_data_rdy_trig,
+                                          &indio_dev->interrupts[0]
+                                          ->ev_list);
+               flush_scheduled_work();
+       } else {
+               iio_add_event_to_list(&iio_event_data_rdy_trig,
+                                     &indio_dev->interrupts[0]->ev_list);
+       }
+       return ret;
+}
+
+/**
+ * adis16204_trig_try_reen() try renabling irq for data rdy trigger
+ * @trig:      the datardy trigger
+ **/
+static int adis16204_trig_try_reen(struct iio_trigger *trig)
+{
+       struct adis16204_state *st = trig->private_data;
+       enable_irq(st->us->irq);
+       return 0;
+}
+
+int adis16204_probe_trigger(struct iio_dev *indio_dev)
+{
+       int ret;
+       struct adis16204_state *st = indio_dev->dev_data;
+
+       st->trig = iio_allocate_trigger();
+       st->trig->name = kasprintf(GFP_KERNEL,
+                               "adis16204-dev%d",
+                               indio_dev->id);
+       if (!st->trig->name) {
+               ret = -ENOMEM;
+               goto error_free_trig;
+       }
+       st->trig->dev.parent = &st->us->dev;
+       st->trig->owner = THIS_MODULE;
+       st->trig->private_data = st;
+       st->trig->set_trigger_state = &adis16204_data_rdy_trigger_set_state;
+       st->trig->try_reenable = &adis16204_trig_try_reen;
+       st->trig->control_attrs = &adis16204_trigger_attr_group;
+       ret = iio_trigger_register(st->trig);
+
+       /* select default trigger */
+       indio_dev->trig = st->trig;
+       if (ret)
+               goto error_free_trig_name;
+
+       return 0;
+
+error_free_trig_name:
+       kfree(st->trig->name);
+error_free_trig:
+       iio_free_trigger(st->trig);
+
+       return ret;
+}
+
+void adis16204_remove_trigger(struct iio_dev *indio_dev)
+{
+       struct adis16204_state *state = indio_dev->dev_data;
+
+       iio_trigger_unregister(state->trig);
+       kfree(state->trig->name);
+       iio_free_trigger(state->trig);
+}
index 033135c6f22661fe0ada0cf28f5d6cfc9d89ade7..8eba0af98ed5ef0f2cd27ca3cce9586144bdcc98 100644 (file)
@@ -105,7 +105,7 @@ static int adis16209_read_ring_data(struct device *dev, u8 *rx)
                xfers[i].bits_per_word = 8;
                xfers[i].cs_change = 1;
                xfers[i].len = 2;
-               xfers[i].delay_usecs = 20;
+               xfers[i].delay_usecs = 30;
                xfers[i].tx_buf = st->tx + 2 * i;
                st->tx[2 * i]
                        = ADIS16209_READ_REG(ADIS16209_SUPPLY_OUT + 2 * i);
index acb67677e563f5342e06fd21594a2bdafb570fa1..9ca6565d2bae7f52de24f8358553db403845dabe 100644 (file)
@@ -27,6 +27,41 @@ config MAX1363_RING_BUFFER
          Say yes here to include ring buffer support in the MAX1363
          ADC driver.
 
+config AD7150
+       tristate "Analog Devices ad7150/1/6 capacitive sensor driver"
+       depends on I2C
+       help
+         Say yes here to build support for Analog Devices capacitive sensors.
+         (ad7150, ad7151, ad7156) Provides direct access via sysfs.
+
+config AD7152
+       tristate "Analog Devices ad7152/3 capacitive sensor driver"
+       depends on I2C
+       help
+         Say yes here to build support for Analog Devices capacitive sensors.
+         (ad7152, ad7153) Provides direct access via sysfs.
+
+config AD7291
+       tristate "Analog Devices AD7291 temperature sensor driver"
+       depends on I2C
+       help
+         Say yes here to build support for Analog Devices AD7291
+         temperature sensors.
+
+config AD7298
+       tristate "Analog Devices AD7298 temperature sensor and ADC driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices AD7298
+         temperature sensors and ADC.
+
+config AD7314
+       tristate "Analog Devices AD7314 temperature sensor driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices AD7314
+         temperature sensors.
+
 config AD799X
        tristate "Analog Devices AD799x ADC driver"
        depends on I2C
@@ -50,9 +85,9 @@ config AD799X_RING_BUFFER
 config AD7476
        tristate "Analog Devices AD7475/6/7/8 AD7466/7/8 and AD7495 ADC driver"
        depends on SPI
-       select IIO_RING_BUFFER  
+       select IIO_RING_BUFFER
        select IIO_SW_RING
-       select IIO_TRIGGER      
+       select IIO_TRIGGER
        help
          Say yes here to build support for Analog Devices
          AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468, AD7495
@@ -61,3 +96,41 @@ config AD7476
 
          To compile this driver as a module, choose M here: the
          module will be called ad7476.
+
+config AD7745
+       tristate "Analog Devices AD7745, AD7746 AD7747 capacitive sensor driver"
+       depends on I2C
+       help
+         Say yes here to build support for Analog Devices capacitive sensors.
+         (AD7745, AD7746, AD7747) Provides direct access via sysfs.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ad7745.
+
+config AD7816
+       tristate "Analog Devices AD7816/7/8 temperature sensor and ADC driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices AD7816/7/8
+         temperature sensors and ADC.
+
+config ADT75
+       tristate "Analog Devices ADT75 temperature sensor driver"
+       depends on I2C
+       help
+         Say yes here to build support for Analog Devices ADT75
+         temperature sensors.
+
+config ADT7310
+       tristate "Analog Devices ADT7310 temperature sensor driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices ADT7310
+         temperature sensors.
+
+config ADT7410
+       tristate "Analog Devices ADT7410 temperature sensor driver"
+       depends on I2C
+       help
+         Say yes here to build support for Analog Devices ADT7410
+         temperature sensors.
index b62c319bcedd1f7872535dc40114fbb7a96a397f..a7dce6bd5f3a498d3d3363271ce2b4ecda15f3c4 100644 (file)
@@ -14,3 +14,14 @@ obj-$(CONFIG_AD799X) += ad799x.o
 ad7476-y := ad7476_core.o
 ad7476-$(CONFIG_IIO_RING_BUFFER) += ad7476_ring.o
 obj-$(CONFIG_AD7476) += ad7476.o
+
+obj-$(CONFIG_AD7150) += ad7150.o
+obj-$(CONFIG_AD7152) += ad7152.o
+obj-$(CONFIG_AD7291) += ad7291.o
+obj-$(CONFIG_AD7298) += ad7298.o
+obj-$(CONFIG_AD7314) += ad7314.o
+obj-$(CONFIG_AD7745) += ad7745.o
+obj-$(CONFIG_AD7816) += ad7816.o
+obj-$(CONFIG_ADT75) += adt75.o
+obj-$(CONFIG_ADT7310) += adt7310.o
+obj-$(CONFIG_ADT7410) += adt7410.o
diff --git a/drivers/staging/iio/adc/ad7150.c b/drivers/staging/iio/adc/ad7150.c
new file mode 100644 (file)
index 0000000..8555766
--- /dev/null
@@ -0,0 +1,877 @@
+/*
+ * AD7150 capacitive sensor driver supporting AD7150/1/6
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * AD7150 registers definition
+ */
+
+#define AD7150_STATUS              0
+#define AD7150_STATUS_OUT1         (1 << 3)
+#define AD7150_STATUS_OUT2         (1 << 5)
+#define AD7150_CH1_DATA_HIGH       1
+#define AD7150_CH1_DATA_LOW        2
+#define AD7150_CH2_DATA_HIGH       3
+#define AD7150_CH2_DATA_LOW        4
+#define AD7150_CH1_AVG_HIGH        5
+#define AD7150_CH1_AVG_LOW         6
+#define AD7150_CH2_AVG_HIGH        7
+#define AD7150_CH2_AVG_LOW         8
+#define AD7150_CH1_SENSITIVITY     9
+#define AD7150_CH1_THR_HOLD_H      9
+#define AD7150_CH1_TIMEOUT         10
+#define AD7150_CH1_THR_HOLD_L      10
+#define AD7150_CH1_SETUP           11
+#define AD7150_CH2_SENSITIVITY     12
+#define AD7150_CH2_THR_HOLD_H      12
+#define AD7150_CH2_TIMEOUT         13
+#define AD7150_CH2_THR_HOLD_L      13
+#define AD7150_CH2_SETUP           14
+#define AD7150_CFG                 15
+#define AD7150_CFG_FIX             (1 << 7)
+#define AD7150_PD_TIMER            16
+#define AD7150_CH1_CAPDAC          17
+#define AD7150_CH2_CAPDAC          18
+#define AD7150_SN3                 19
+#define AD7150_SN2                 20
+#define AD7150_SN1                 21
+#define AD7150_SN0                 22
+#define AD7150_ID                  23
+
+#define AD7150_MAX_CONV_MODE       4
+
+/*
+ * struct ad7150_chip_info - chip specifc information
+ */
+
+struct ad7150_chip_info {
+       const char *name;
+       struct i2c_client *client;
+       struct iio_dev *indio_dev;
+       struct work_struct thresh_work;
+       bool inter;
+       s64 last_timestamp;
+       u16 ch1_threshold;     /* Ch1 Threshold (in fixed threshold mode) */
+       u8  ch1_sensitivity;   /* Ch1 Sensitivity (in adaptive threshold mode) */
+       u8  ch1_timeout;       /* Ch1 Timeout (in adaptive threshold mode) */
+       u8  ch1_setup;
+       u16 ch2_threshold;     /* Ch2 Threshold (in fixed threshold mode) */
+       u8  ch2_sensitivity;   /* Ch1 Sensitivity (in adaptive threshold mode) */
+       u8  ch2_timeout;       /* Ch1 Timeout (in adaptive threshold mode) */
+       u8  ch2_setup;
+       u8  powerdown_timer;
+       char threshold_mode[10]; /* adaptive/fixed threshold mode */
+       int old_state;
+       char *conversion_mode;
+};
+
+struct ad7150_conversion_mode {
+       char *name;
+       u8 reg_cfg;
+};
+
+struct ad7150_conversion_mode ad7150_conv_mode_table[AD7150_MAX_CONV_MODE] = {
+       { "idle", 0 },
+       { "continuous-conversion", 1 },
+       { "single-conversion", 2 },
+       { "power-down", 3 },
+};
+
+/*
+ * ad7150 register access by I2C
+ */
+
+static int ad7150_i2c_read(struct ad7150_chip_info *chip, u8 reg, u8 *data, int len)
+{
+       struct i2c_client *client = chip->client;
+       int ret = 0;
+
+       ret = i2c_master_send(client, &reg, 1);
+       if (ret < 0) {
+               dev_err(&client->dev, "I2C write error\n");
+               return ret;
+       }
+
+       ret = i2c_master_recv(client, data, len);
+       if (ret < 0) {
+               dev_err(&client->dev, "I2C read error\n");
+               return ret;
+       }
+
+       return ret;
+}
+
+static int ad7150_i2c_write(struct ad7150_chip_info *chip, u8 reg, u8 data)
+{
+       struct i2c_client *client = chip->client;
+       int ret = 0;
+
+       u8 tx[2] = {
+               reg,
+               data,
+       };
+
+       ret = i2c_master_send(client, tx, 2);
+       if (ret < 0)
+               dev_err(&client->dev, "I2C write error\n");
+
+       return ret;
+}
+
+/*
+ * sysfs nodes
+ */
+
+#define IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(_show)                             \
+       IIO_DEVICE_ATTR(available_conversion_modes, S_IRUGO, _show, NULL, 0)
+#define IIO_DEV_ATTR_CONVERSION_MODE(_mode, _show, _store)              \
+       IIO_DEVICE_ATTR(conversion_mode, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_AVAIL_THRESHOLD_MODES(_show)                              \
+       IIO_DEVICE_ATTR(available_threshold_modes, S_IRUGO, _show, NULL, 0)
+#define IIO_DEV_ATTR_THRESHOLD_MODE(_mode, _show, _store)              \
+       IIO_DEVICE_ATTR(threshold_mode, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH1_THRESHOLD(_mode, _show, _store)              \
+       IIO_DEVICE_ATTR(ch1_threshold, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH2_THRESHOLD(_mode, _show, _store)              \
+       IIO_DEVICE_ATTR(ch2_threshold, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH1_SENSITIVITY(_mode, _show, _store)             \
+       IIO_DEVICE_ATTR(ch1_sensitivity, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH2_SENSITIVITY(_mode, _show, _store)             \
+       IIO_DEVICE_ATTR(ch2_sensitivity, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH1_TIMEOUT(_mode, _show, _store)         \
+       IIO_DEVICE_ATTR(ch1_timeout, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH2_TIMEOUT(_mode, _show, _store)         \
+       IIO_DEVICE_ATTR(ch2_timeout, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH1_VALUE(_show)          \
+       IIO_DEVICE_ATTR(ch1_value, S_IRUGO, _show, NULL, 0)
+#define IIO_DEV_ATTR_CH2_VALUE(_show)          \
+       IIO_DEVICE_ATTR(ch2_value, S_IRUGO, _show, NULL, 0)
+#define IIO_DEV_ATTR_CH1_SETUP(_mode, _show, _store)           \
+       IIO_DEVICE_ATTR(ch1_setup, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH2_SETUP(_mode, _show, _store)              \
+       IIO_DEVICE_ATTR(ch2_setup, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_POWERDOWN_TIMER(_mode, _show, _store)              \
+       IIO_DEVICE_ATTR(powerdown_timer, _mode, _show, _store, 0)
+
+static ssize_t ad7150_show_conversion_modes(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int i;
+       int len = 0;
+
+       for (i = 0; i < AD7150_MAX_CONV_MODE; i++)
+               len += sprintf(buf + len, "%s\n", ad7150_conv_mode_table[i].name);
+
+       return len;
+}
+
+static IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(ad7150_show_conversion_modes);
+
+static ssize_t ad7150_show_conversion_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%s\n", chip->conversion_mode);
+}
+
+static ssize_t ad7150_store_conversion_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+       u8 cfg;
+       int i;
+
+       ad7150_i2c_read(chip, AD7150_CFG, &cfg, 1);
+
+       for (i = 0; i < AD7150_MAX_CONV_MODE; i++) {
+               if (strncmp(buf, ad7150_conv_mode_table[i].name,
+                               strlen(ad7150_conv_mode_table[i].name) - 1) == 0) {
+                       chip->conversion_mode = ad7150_conv_mode_table[i].name;
+                       cfg |= 0x18 | ad7150_conv_mode_table[i].reg_cfg;
+                       ad7150_i2c_write(chip, AD7150_CFG, cfg);
+                       return len;
+               }
+       }
+
+       dev_err(dev, "not supported conversion mode\n");
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CONVERSION_MODE(S_IRUGO | S_IWUSR,
+               ad7150_show_conversion_mode,
+               ad7150_store_conversion_mode);
+
+static ssize_t ad7150_show_threshold_modes(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return sprintf(buf, "adaptive\nfixed\n");
+}
+
+static IIO_DEV_ATTR_AVAIL_THRESHOLD_MODES(ad7150_show_threshold_modes);
+
+static ssize_t ad7150_show_ch1_value(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+       u8 data[2];
+
+       ad7150_i2c_read(chip, AD7150_CH1_DATA_HIGH, data, 2);
+       return sprintf(buf, "%d\n", ((int) data[0] << 8) | data[1]);
+}
+
+static IIO_DEV_ATTR_CH1_VALUE(ad7150_show_ch1_value);
+
+static ssize_t ad7150_show_ch2_value(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+       u8 data[2];
+
+       ad7150_i2c_read(chip, AD7150_CH2_DATA_HIGH, data, 2);
+       return sprintf(buf, "%d\n", ((int) data[0] << 8) | data[1]);
+}
+
+static IIO_DEV_ATTR_CH2_VALUE(ad7150_show_ch2_value);
+
+static ssize_t ad7150_show_threshold_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%s\n", chip->threshold_mode);
+}
+
+static ssize_t ad7150_store_threshold_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+       u8 cfg;
+
+       ad7150_i2c_read(chip, AD7150_CFG, &cfg, 1);
+
+       if (strncmp(buf, "fixed", 5) == 0) {
+               strcpy(chip->threshold_mode, "fixed");
+               cfg |= AD7150_CFG_FIX;
+               ad7150_i2c_write(chip, AD7150_CFG, cfg);
+
+               return len;
+       } else if (strncmp(buf, "adaptive", 8) == 0) {
+               strcpy(chip->threshold_mode, "adaptive");
+               cfg &= ~AD7150_CFG_FIX;
+               ad7150_i2c_write(chip, AD7150_CFG, cfg);
+
+               return len;
+       }
+
+       dev_err(dev, "not supported threshold mode\n");
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_THRESHOLD_MODE(S_IRUGO | S_IWUSR,
+               ad7150_show_threshold_mode,
+               ad7150_store_threshold_mode);
+
+static ssize_t ad7150_show_ch1_threshold(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", chip->ch1_threshold);
+}
+
+static ssize_t ad7150_store_ch1_threshold(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x10000)) {
+               ad7150_i2c_write(chip, AD7150_CH1_THR_HOLD_H, data >> 8);
+               ad7150_i2c_write(chip, AD7150_CH1_THR_HOLD_L, data);
+               chip->ch1_threshold = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH1_THRESHOLD(S_IRUGO | S_IWUSR,
+               ad7150_show_ch1_threshold,
+               ad7150_store_ch1_threshold);
+
+static ssize_t ad7150_show_ch2_threshold(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", chip->ch2_threshold);
+}
+
+static ssize_t ad7150_store_ch2_threshold(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x10000)) {
+               ad7150_i2c_write(chip, AD7150_CH2_THR_HOLD_H, data >> 8);
+               ad7150_i2c_write(chip, AD7150_CH2_THR_HOLD_L, data);
+               chip->ch2_threshold = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH2_THRESHOLD(S_IRUGO | S_IWUSR,
+               ad7150_show_ch2_threshold,
+               ad7150_store_ch2_threshold);
+
+static ssize_t ad7150_show_ch1_sensitivity(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", chip->ch1_sensitivity);
+}
+
+static ssize_t ad7150_store_ch1_sensitivity(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x100)) {
+               ad7150_i2c_write(chip, AD7150_CH1_SENSITIVITY, data);
+               chip->ch1_sensitivity = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH1_SENSITIVITY(S_IRUGO | S_IWUSR,
+               ad7150_show_ch1_sensitivity,
+               ad7150_store_ch1_sensitivity);
+
+static ssize_t ad7150_show_ch2_sensitivity(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", chip->ch2_sensitivity);
+}
+
+static ssize_t ad7150_store_ch2_sensitivity(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x100)) {
+               ad7150_i2c_write(chip, AD7150_CH2_SENSITIVITY, data);
+               chip->ch2_sensitivity = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH2_SENSITIVITY(S_IRUGO | S_IWUSR,
+               ad7150_show_ch2_sensitivity,
+               ad7150_store_ch2_sensitivity);
+
+static ssize_t ad7150_show_ch1_timeout(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", chip->ch1_timeout);
+}
+
+static ssize_t ad7150_store_ch1_timeout(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x100)) {
+               ad7150_i2c_write(chip, AD7150_CH1_TIMEOUT, data);
+               chip->ch1_timeout = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH1_TIMEOUT(S_IRUGO | S_IWUSR,
+               ad7150_show_ch1_timeout,
+               ad7150_store_ch1_timeout);
+
+static ssize_t ad7150_show_ch2_timeout(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", chip->ch2_timeout);
+}
+
+static ssize_t ad7150_store_ch2_timeout(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x100)) {
+               ad7150_i2c_write(chip, AD7150_CH2_TIMEOUT, data);
+               chip->ch2_timeout = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH2_TIMEOUT(S_IRUGO | S_IWUSR,
+               ad7150_show_ch2_timeout,
+               ad7150_store_ch2_timeout);
+
+static ssize_t ad7150_show_ch1_setup(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "0x%02x\n", chip->ch1_setup);
+}
+
+static ssize_t ad7150_store_ch1_setup(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x100)) {
+               ad7150_i2c_write(chip, AD7150_CH1_SETUP, data);
+               chip->ch1_setup = data;
+               return len;
+       }
+
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH1_SETUP(S_IRUGO | S_IWUSR,
+               ad7150_show_ch1_setup,
+               ad7150_store_ch1_setup);
+
+static ssize_t ad7150_show_ch2_setup(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "0x%02x\n", chip->ch2_setup);
+}
+
+static ssize_t ad7150_store_ch2_setup(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x100)) {
+               ad7150_i2c_write(chip, AD7150_CH2_SETUP, data);
+               chip->ch2_setup = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH2_SETUP(S_IRUGO | S_IWUSR,
+               ad7150_show_ch2_setup,
+               ad7150_store_ch2_setup);
+
+static ssize_t ad7150_show_name(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+       return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad7150_show_name, NULL, 0);
+
+static ssize_t ad7150_show_powerdown_timer(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "0x%02x\n", chip->powerdown_timer);
+}
+
+static ssize_t ad7150_store_powerdown_timer(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x40)) {
+               chip->powerdown_timer = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_POWERDOWN_TIMER(S_IRUGO | S_IWUSR,
+               ad7150_show_powerdown_timer,
+               ad7150_store_powerdown_timer);
+
+static struct attribute *ad7150_attributes[] = {
+       &iio_dev_attr_available_threshold_modes.dev_attr.attr,
+       &iio_dev_attr_threshold_mode.dev_attr.attr,
+       &iio_dev_attr_ch1_threshold.dev_attr.attr,
+       &iio_dev_attr_ch2_threshold.dev_attr.attr,
+       &iio_dev_attr_ch1_timeout.dev_attr.attr,
+       &iio_dev_attr_ch2_timeout.dev_attr.attr,
+       &iio_dev_attr_ch1_setup.dev_attr.attr,
+       &iio_dev_attr_ch2_setup.dev_attr.attr,
+       &iio_dev_attr_ch1_sensitivity.dev_attr.attr,
+       &iio_dev_attr_ch2_sensitivity.dev_attr.attr,
+       &iio_dev_attr_powerdown_timer.dev_attr.attr,
+       &iio_dev_attr_ch1_value.dev_attr.attr,
+       &iio_dev_attr_ch2_value.dev_attr.attr,
+       &iio_dev_attr_name.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ad7150_attribute_group = {
+       .attrs = ad7150_attributes,
+};
+
+/*
+ * threshold events
+ */
+
+#define IIO_EVENT_CODE_CH1_HIGH    IIO_BUFFER_EVENT_CODE(0)
+#define IIO_EVENT_CODE_CH1_LOW     IIO_BUFFER_EVENT_CODE(1)
+#define IIO_EVENT_CODE_CH2_HIGH    IIO_BUFFER_EVENT_CODE(2)
+#define IIO_EVENT_CODE_CH2_LOW     IIO_BUFFER_EVENT_CODE(3)
+
+#define IIO_EVENT_ATTR_CH1_HIGH_SH(_evlist, _show, _store, _mask)      \
+       IIO_EVENT_ATTR_SH(ch1_high, _evlist, _show, _store, _mask)
+
+#define IIO_EVENT_ATTR_CH2_HIGH_SH(_evlist, _show, _store, _mask)      \
+       IIO_EVENT_ATTR_SH(ch2_high, _evlist, _show, _store, _mask)
+
+#define IIO_EVENT_ATTR_CH1_LOW_SH(_evlist, _show, _store, _mask)       \
+       IIO_EVENT_ATTR_SH(ch1_low, _evlist, _show, _store, _mask)
+
+#define IIO_EVENT_ATTR_CH2_LOW_SH(_evlist, _show, _store, _mask)       \
+       IIO_EVENT_ATTR_SH(ch2_low, _evlist, _show, _store, _mask)
+
+static void ad7150_interrupt_handler_bh(struct work_struct *work_s)
+{
+       struct ad7150_chip_info *chip =
+               container_of(work_s, struct ad7150_chip_info, thresh_work);
+       u8 int_status;
+
+       enable_irq(chip->client->irq);
+
+       ad7150_i2c_read(chip, AD7150_STATUS, &int_status, 1);
+
+       if ((int_status & AD7150_STATUS_OUT1) && !(chip->old_state & AD7150_STATUS_OUT1))
+               iio_push_event(chip->indio_dev, 0,
+                               IIO_EVENT_CODE_CH1_HIGH,
+                               chip->last_timestamp);
+       else if ((!(int_status & AD7150_STATUS_OUT1)) && (chip->old_state & AD7150_STATUS_OUT1))
+               iio_push_event(chip->indio_dev, 0,
+                               IIO_EVENT_CODE_CH1_LOW,
+                               chip->last_timestamp);
+
+       if ((int_status & AD7150_STATUS_OUT2) && !(chip->old_state & AD7150_STATUS_OUT2))
+               iio_push_event(chip->indio_dev, 0,
+                               IIO_EVENT_CODE_CH2_HIGH,
+                               chip->last_timestamp);
+       else if ((!(int_status & AD7150_STATUS_OUT2)) && (chip->old_state & AD7150_STATUS_OUT2))
+               iio_push_event(chip->indio_dev, 0,
+                               IIO_EVENT_CODE_CH2_LOW,
+                               chip->last_timestamp);
+}
+
+static int ad7150_interrupt_handler_th(struct iio_dev *dev_info,
+               int index,
+               s64 timestamp,
+               int no_test)
+{
+       struct ad7150_chip_info *chip = dev_info->dev_data;
+
+       chip->last_timestamp = timestamp;
+       schedule_work(&chip->thresh_work);
+
+       return 0;
+}
+
+IIO_EVENT_SH(threshold, &ad7150_interrupt_handler_th);
+
+static ssize_t ad7150_query_out_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       /*
+        * AD7150 provides two logic output channels, which can be used as interrupt
+        * but the pins are not configurable
+        */
+       return sprintf(buf, "1\n");
+}
+
+static ssize_t ad7150_set_out_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return len;
+}
+
+IIO_EVENT_ATTR_CH1_HIGH_SH(iio_event_threshold, ad7150_query_out_mode, ad7150_set_out_mode, 0);
+IIO_EVENT_ATTR_CH2_HIGH_SH(iio_event_threshold, ad7150_query_out_mode, ad7150_set_out_mode, 0);
+IIO_EVENT_ATTR_CH1_LOW_SH(iio_event_threshold, ad7150_query_out_mode, ad7150_set_out_mode, 0);
+IIO_EVENT_ATTR_CH2_LOW_SH(iio_event_threshold, ad7150_query_out_mode, ad7150_set_out_mode, 0);
+
+static struct attribute *ad7150_event_attributes[] = {
+       &iio_event_attr_ch1_high.dev_attr.attr,
+       &iio_event_attr_ch2_high.dev_attr.attr,
+       &iio_event_attr_ch1_low.dev_attr.attr,
+       &iio_event_attr_ch2_low.dev_attr.attr,
+       NULL,
+};
+
+static struct attribute_group ad7150_event_attribute_group = {
+       .attrs = ad7150_event_attributes,
+};
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit ad7150_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       int ret = 0, regdone = 0;
+       struct ad7150_chip_info *chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (chip == NULL) {
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+
+       /* this is only used for device removal purposes */
+       i2c_set_clientdata(client, chip);
+
+       chip->client = client;
+       chip->name = id->name;
+
+       chip->indio_dev = iio_allocate_device();
+       if (chip->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_chip;
+       }
+
+       /* Echipabilish that the iio_dev is a child of the i2c device */
+       chip->indio_dev->dev.parent = &client->dev;
+       chip->indio_dev->attrs = &ad7150_attribute_group;
+       chip->indio_dev->event_attrs = &ad7150_event_attribute_group;
+       chip->indio_dev->dev_data = (void *)(chip);
+       chip->indio_dev->driver_module = THIS_MODULE;
+       chip->indio_dev->num_interrupt_lines = 1;
+       chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(chip->indio_dev);
+       if (ret)
+               goto error_free_dev;
+       regdone = 1;
+
+       if (client->irq && gpio_is_valid(irq_to_gpio(client->irq)) > 0) {
+               ret = iio_register_interrupt_line(client->irq,
+                               chip->indio_dev,
+                               0,
+                               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                               "ad7150");
+               if (ret)
+                       goto error_free_dev;
+
+               iio_add_event_to_list(iio_event_attr_ch2_low.listel,
+                               &chip->indio_dev->interrupts[0]->ev_list);
+
+               INIT_WORK(&chip->thresh_work, ad7150_interrupt_handler_bh);
+       }
+
+       dev_err(&client->dev, "%s capacitive sensor registered, irq: %d\n", id->name, client->irq);
+
+       return 0;
+
+error_free_dev:
+       if (regdone)
+               iio_device_unregister(chip->indio_dev);
+       else
+               iio_free_device(chip->indio_dev);
+error_free_chip:
+       kfree(chip);
+error_ret:
+       return ret;
+}
+
+static int __devexit ad7150_remove(struct i2c_client *client)
+{
+       struct ad7150_chip_info *chip = i2c_get_clientdata(client);
+       struct iio_dev *indio_dev = chip->indio_dev;
+
+       if (client->irq && gpio_is_valid(irq_to_gpio(client->irq)) > 0)
+               iio_unregister_interrupt_line(indio_dev, 0);
+       iio_device_unregister(indio_dev);
+       kfree(chip);
+
+       return 0;
+}
+
+static const struct i2c_device_id ad7150_id[] = {
+       { "ad7150", 0 },
+       { "ad7151", 0 },
+       { "ad7156", 0 },
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, ad7150_id);
+
+static struct i2c_driver ad7150_driver = {
+       .driver = {
+               .name = "ad7150",
+       },
+       .probe = ad7150_probe,
+       .remove = __devexit_p(ad7150_remove),
+       .id_table = ad7150_id,
+};
+
+static __init int ad7150_init(void)
+{
+       return i2c_add_driver(&ad7150_driver);
+}
+
+static __exit void ad7150_exit(void)
+{
+       i2c_del_driver(&ad7150_driver);
+}
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ad7150/1/6 capacitive sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(ad7150_init);
+module_exit(ad7150_exit);
diff --git a/drivers/staging/iio/adc/ad7152.c b/drivers/staging/iio/adc/ad7152.c
new file mode 100644 (file)
index 0000000..fa7f840
--- /dev/null
@@ -0,0 +1,610 @@
+/*
+ * AD7152 capacitive sensor driver supporting AD7152/3
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * AD7152 registers definition
+ */
+
+#define AD7152_STATUS              0
+#define AD7152_STATUS_RDY1         (1 << 0)
+#define AD7152_STATUS_RDY2         (1 << 1)
+#define AD7152_CH1_DATA_HIGH       1
+#define AD7152_CH1_DATA_LOW        2
+#define AD7152_CH2_DATA_HIGH       3
+#define AD7152_CH2_DATA_LOW        4
+#define AD7152_CH1_OFFS_HIGH       5
+#define AD7152_CH1_OFFS_LOW        6
+#define AD7152_CH2_OFFS_HIGH       7
+#define AD7152_CH2_OFFS_LOW        8
+#define AD7152_CH1_GAIN_HIGH       9
+#define AD7152_CH1_GAIN_LOW        10
+#define AD7152_CH1_SETUP           11
+#define AD7152_CH2_GAIN_HIGH       12
+#define AD7152_CH2_GAIN_LOW        13
+#define AD7152_CH2_SETUP           14
+#define AD7152_CFG                 15
+#define AD7152_RESEVERD            16
+#define AD7152_CAPDAC_POS          17
+#define AD7152_CAPDAC_NEG          18
+#define AD7152_CFG2                26
+
+#define AD7152_MAX_CONV_MODE       6
+
+/*
+ * struct ad7152_chip_info - chip specifc information
+ */
+
+struct ad7152_chip_info {
+       const char *name;
+       struct i2c_client *client;
+       struct iio_dev *indio_dev;
+       u16 ch1_offset;     /* Channel 1 offset calibration coefficient */
+       u16 ch1_gain;       /* Channel 1 gain coefficient */
+       u8  ch1_setup;
+       u16 ch2_offset;     /* Channel 2 offset calibration coefficient */
+       u16 ch2_gain;       /* Channel 1 gain coefficient */
+       u8  ch2_setup;
+       u8  filter_rate_setup; /* Capacitive channel digital filter setup; conversion time/update rate setup per channel */
+       char *conversion_mode;
+};
+
+struct ad7152_conversion_mode {
+       char *name;
+       u8 reg_cfg;
+};
+
+struct ad7152_conversion_mode ad7152_conv_mode_table[AD7152_MAX_CONV_MODE] = {
+       { "idle", 0 },
+       { "continuous-conversion", 1 },
+       { "single-conversion", 2 },
+       { "power-down", 3 },
+       { "offset-calibration", 5 },
+       { "gain-calibration", 6 },
+};
+
+/*
+ * ad7152 register access by I2C
+ */
+
+static int ad7152_i2c_read(struct ad7152_chip_info *chip, u8 reg, u8 *data, int len)
+{
+       struct i2c_client *client = chip->client;
+       int ret;
+
+       ret = i2c_master_send(client, &reg, 1);
+       if (ret < 0) {
+               dev_err(&client->dev, "I2C write error\n");
+               return ret;
+       }
+
+       ret = i2c_master_recv(client, data, len);
+       if (ret < 0) {
+               dev_err(&client->dev, "I2C read error\n");
+       }
+
+       return ret;
+}
+
+static int ad7152_i2c_write(struct ad7152_chip_info *chip, u8 reg, u8 data)
+{
+       struct i2c_client *client = chip->client;
+       int ret;
+
+       u8 tx[2] = {
+               reg,
+               data,
+       };
+
+       ret = i2c_master_send(client, tx, 2);
+       if (ret < 0)
+               dev_err(&client->dev, "I2C write error\n");
+
+       return ret;
+}
+
+/*
+ * sysfs nodes
+ */
+
+#define IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(_show)                             \
+       IIO_DEVICE_ATTR(available_conversion_modes, S_IRUGO, _show, NULL, 0)
+#define IIO_DEV_ATTR_CONVERSION_MODE(_mode, _show, _store)              \
+       IIO_DEVICE_ATTR(conversion_mode, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH1_OFFSET(_mode, _show, _store)          \
+       IIO_DEVICE_ATTR(ch1_offset, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH2_OFFSET(_mode, _show, _store)          \
+       IIO_DEVICE_ATTR(ch2_offset, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH1_GAIN(_mode, _show, _store)            \
+       IIO_DEVICE_ATTR(ch1_gain, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH2_GAIN(_mode, _show, _store)            \
+       IIO_DEVICE_ATTR(ch2_gain, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH1_VALUE(_show)          \
+       IIO_DEVICE_ATTR(ch1_value, S_IRUGO, _show, NULL, 0)
+#define IIO_DEV_ATTR_CH2_VALUE(_show)          \
+       IIO_DEVICE_ATTR(ch2_value, S_IRUGO, _show, NULL, 0)
+#define IIO_DEV_ATTR_CH1_SETUP(_mode, _show, _store)           \
+       IIO_DEVICE_ATTR(ch1_setup, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CH2_SETUP(_mode, _show, _store)              \
+       IIO_DEVICE_ATTR(ch2_setup, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_FILTER_RATE_SETUP(_mode, _show, _store)              \
+       IIO_DEVICE_ATTR(filter_rate_setup, _mode, _show, _store, 0)
+
+static ssize_t ad7152_show_conversion_modes(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int i;
+       int len = 0;
+
+       for (i = 0; i < AD7152_MAX_CONV_MODE; i++)
+               len += sprintf(buf + len, "%s ", ad7152_conv_mode_table[i].name);
+
+       len += sprintf(buf + len, "\n");
+
+       return len;
+}
+
+static IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(ad7152_show_conversion_modes);
+
+static ssize_t ad7152_show_ch1_value(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7152_chip_info *chip = dev_info->dev_data;
+       u8 data[2];
+
+       ad7152_i2c_read(chip, AD7152_CH1_DATA_HIGH, data, 2);
+       return sprintf(buf, "%d\n", ((int)data[0] << 8) | data[1]);
+}
+
+static IIO_DEV_ATTR_CH1_VALUE(ad7152_show_ch1_value);
+
+static ssize_t ad7152_show_ch2_value(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7152_chip_info *chip = dev_info->dev_data;
+       u8 data[2];
+
+       ad7152_i2c_read(chip, AD7152_CH2_DATA_HIGH, data, 2);
+       return sprintf(buf, "%d\n", ((int)data[0] << 8) | data[1]);
+}
+
+static IIO_DEV_ATTR_CH2_VALUE(ad7152_show_ch2_value);
+
+static ssize_t ad7152_show_conversion_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7152_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%s\n", chip->conversion_mode);
+}
+
+static ssize_t ad7152_store_conversion_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7152_chip_info *chip = dev_info->dev_data;
+       u8 cfg;
+       int i;
+
+       ad7152_i2c_read(chip, AD7152_CFG, &cfg, 1);
+
+       for (i = 0; i < AD7152_MAX_CONV_MODE; i++)
+               if (strncmp(buf, ad7152_conv_mode_table[i].name,
+                               strlen(ad7152_conv_mode_table[i].name) - 1) == 0) {
+                       chip->conversion_mode = ad7152_conv_mode_table[i].name;
+                       cfg |= 0x18 | ad7152_conv_mode_table[i].reg_cfg;
+                       ad7152_i2c_write(chip, AD7152_CFG, cfg);
+                       return len;
+               }
+
+       dev_err(dev, "not supported conversion mode\n");
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CONVERSION_MODE(S_IRUGO | S_IWUSR,
+               ad7152_show_conversion_mode,
+               ad7152_store_conversion_mode);
+
+static ssize_t ad7152_show_ch1_offset(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7152_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", chip->ch1_offset);
+}
+
+static ssize_t ad7152_store_ch1_offset(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7152_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x10000)) {
+               ad7152_i2c_write(chip, AD7152_CH1_OFFS_HIGH, data >> 8);
+               ad7152_i2c_write(chip, AD7152_CH1_OFFS_LOW, data);
+               chip->ch1_offset = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH1_OFFSET(S_IRUGO | S_IWUSR,
+               ad7152_show_ch1_offset,
+               ad7152_store_ch1_offset);
+
+static ssize_t ad7152_show_ch2_offset(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7152_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", chip->ch2_offset);
+}
+
+static ssize_t ad7152_store_ch2_offset(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7152_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x10000)) {
+               ad7152_i2c_write(chip, AD7152_CH2_OFFS_HIGH, data >> 8);
+               ad7152_i2c_write(chip, AD7152_CH2_OFFS_LOW, data);
+               chip->ch2_offset = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH2_OFFSET(S_IRUGO | S_IWUSR,
+               ad7152_show_ch2_offset,
+               ad7152_store_ch2_offset);
+
+static ssize_t ad7152_show_ch1_gain(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7152_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", chip->ch1_gain);
+}
+
+static ssize_t ad7152_store_ch1_gain(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7152_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x10000)) {
+               ad7152_i2c_write(chip, AD7152_CH1_GAIN_HIGH, data >> 8);
+               ad7152_i2c_write(chip, AD7152_CH1_GAIN_LOW, data);
+               chip->ch1_gain = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH1_GAIN(S_IRUGO | S_IWUSR,
+               ad7152_show_ch1_gain,
+               ad7152_store_ch1_gain);
+
+static ssize_t ad7152_show_ch2_gain(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7152_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", chip->ch2_gain);
+}
+
+static ssize_t ad7152_store_ch2_gain(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7152_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x10000)) {
+               ad7152_i2c_write(chip, AD7152_CH2_GAIN_HIGH, data >> 8);
+               ad7152_i2c_write(chip, AD7152_CH2_GAIN_LOW, data);
+               chip->ch2_gain = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH2_GAIN(S_IRUGO | S_IWUSR,
+               ad7152_show_ch2_gain,
+               ad7152_store_ch2_gain);
+
+static ssize_t ad7152_show_ch1_setup(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7152_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "0x%02x\n", chip->ch1_setup);
+}
+
+static ssize_t ad7152_store_ch1_setup(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7152_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x100)) {
+               ad7152_i2c_write(chip, AD7152_CH1_SETUP, data);
+               chip->ch1_setup = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH1_SETUP(S_IRUGO | S_IWUSR,
+               ad7152_show_ch1_setup,
+               ad7152_store_ch1_setup);
+
+static ssize_t ad7152_show_ch2_setup(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7152_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "0x%02x\n", chip->ch2_setup);
+}
+
+static ssize_t ad7152_store_ch2_setup(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7152_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x100)) {
+               ad7152_i2c_write(chip, AD7152_CH2_SETUP, data);
+               chip->ch2_setup = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CH2_SETUP(S_IRUGO | S_IWUSR,
+               ad7152_show_ch2_setup,
+               ad7152_store_ch2_setup);
+
+static ssize_t ad7152_show_filter_rate_setup(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7152_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "0x%02x\n", chip->filter_rate_setup);
+}
+
+static ssize_t ad7152_store_filter_rate_setup(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7152_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x100)) {
+               ad7152_i2c_write(chip, AD7152_CFG2, data);
+               chip->filter_rate_setup = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_FILTER_RATE_SETUP(S_IRUGO | S_IWUSR,
+               ad7152_show_filter_rate_setup,
+               ad7152_store_filter_rate_setup);
+
+static ssize_t ad7152_show_name(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7152_chip_info *chip = dev_info->dev_data;
+       return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad7152_show_name, NULL, 0);
+
+static struct attribute *ad7152_attributes[] = {
+       &iio_dev_attr_available_conversion_modes.dev_attr.attr,
+       &iio_dev_attr_conversion_mode.dev_attr.attr,
+       &iio_dev_attr_ch1_gain.dev_attr.attr,
+       &iio_dev_attr_ch2_gain.dev_attr.attr,
+       &iio_dev_attr_ch1_offset.dev_attr.attr,
+       &iio_dev_attr_ch2_offset.dev_attr.attr,
+       &iio_dev_attr_ch1_value.dev_attr.attr,
+       &iio_dev_attr_ch2_value.dev_attr.attr,
+       &iio_dev_attr_ch1_setup.dev_attr.attr,
+       &iio_dev_attr_ch2_setup.dev_attr.attr,
+       &iio_dev_attr_filter_rate_setup.dev_attr.attr,
+       &iio_dev_attr_name.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ad7152_attribute_group = {
+       .attrs = ad7152_attributes,
+};
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit ad7152_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       int ret = 0;
+       struct ad7152_chip_info *chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (chip == NULL) {
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+
+       /* this is only used for device removal purposes */
+       i2c_set_clientdata(client, chip);
+
+       chip->client = client;
+       chip->name = id->name;
+
+       chip->indio_dev = iio_allocate_device();
+       if (chip->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_chip;
+       }
+
+       /* Echipabilish that the iio_dev is a child of the i2c device */
+       chip->indio_dev->dev.parent = &client->dev;
+       chip->indio_dev->attrs = &ad7152_attribute_group;
+       chip->indio_dev->dev_data = (void *)(chip);
+       chip->indio_dev->driver_module = THIS_MODULE;
+       chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(chip->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       dev_err(&client->dev, "%s capacitive sensor registered\n", id->name);
+
+       return 0;
+
+error_free_dev:
+       iio_free_device(chip->indio_dev);
+error_free_chip:
+       kfree(chip);
+error_ret:
+       return ret;
+}
+
+static int __devexit ad7152_remove(struct i2c_client *client)
+{
+       struct ad7152_chip_info *chip = i2c_get_clientdata(client);
+       struct iio_dev *indio_dev = chip->indio_dev;
+
+       if (client->irq && gpio_is_valid(irq_to_gpio(client->irq)) > 0)
+               iio_unregister_interrupt_line(indio_dev, 0);
+       iio_device_unregister(indio_dev);
+       kfree(chip);
+
+       return 0;
+}
+
+static const struct i2c_device_id ad7152_id[] = {
+       { "ad7152", 0 },
+       { "ad7153", 0 },
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, ad7152_id);
+
+static struct i2c_driver ad7152_driver = {
+       .driver = {
+               .name = "ad7152",
+       },
+       .probe = ad7152_probe,
+       .remove = __devexit_p(ad7152_remove),
+       .id_table = ad7152_id,
+};
+
+static __init int ad7152_init(void)
+{
+       return i2c_add_driver(&ad7152_driver);
+}
+
+static __exit void ad7152_exit(void)
+{
+       i2c_del_driver(&ad7152_driver);
+}
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ad7152/3 capacitive sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(ad7152_init);
+module_exit(ad7152_exit);
diff --git a/drivers/staging/iio/adc/ad7291.c b/drivers/staging/iio/adc/ad7291.c
new file mode 100644 (file)
index 0000000..34041a7
--- /dev/null
@@ -0,0 +1,1039 @@
+/*
+ * AD7291 digital temperature sensor driver supporting AD7291
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * AD7291 registers definition
+ */
+#define AD7291_COMMAND                 0
+#define AD7291_VOLTAGE                 1
+#define AD7291_T_SENSE                 2
+#define AD7291_T_AVERAGE               3
+#define AD7291_VOLTAGE_LIMIT_BASE      4
+#define AD7291_VOLTAGE_LIMIT_COUNT     8
+#define AD7291_T_SENSE_HIGH            0x1c
+#define AD7291_T_SENSE_LOW             0x1d
+#define AD7291_T_SENSE_HYST            0x1e
+#define AD7291_VOLTAGE_ALERT_STATUS    0x1f
+#define AD7291_T_ALERT_STATUS          0x20
+
+/*
+ * AD7291 command
+ */
+#define AD7291_AUTOCYCLE               0x1
+#define AD7291_RESET                   0x2
+#define AD7291_ALART_CLEAR             0x4
+#define AD7291_ALART_POLARITY          0x8
+#define AD7291_EXT_REF                 0x10
+#define AD7291_NOISE_DELAY             0x20
+#define AD7291_T_SENSE_MASK            0x40
+#define AD7291_VOLTAGE_MASK            0xff00
+#define AD7291_VOLTAGE_OFFSET          0x8
+
+/*
+ * AD7291 value masks
+ */
+#define AD7291_CHANNEL_MASK            0xf000
+#define AD7291_VALUE_MASK              0xfff
+#define AD7291_T_VALUE_SIGN            0x400
+#define AD7291_T_VALUE_FLOAT_OFFSET    2
+#define AD7291_T_VALUE_FLOAT_MASK      0x2
+
+/*
+ * struct ad7291_chip_info - chip specifc information
+ */
+
+struct ad7291_chip_info {
+       const char *name;
+       struct i2c_client *client;
+       struct iio_dev *indio_dev;
+       struct work_struct thresh_work;
+       s64 last_timestamp;
+       u16 command;
+       u8  channels;   /* Active voltage channels */
+};
+
+/*
+ * struct ad7291_chip_info - chip specifc information
+ */
+
+struct ad7291_limit_regs {
+       u16     data_high;
+       u16     data_low;
+       u16     hysteresis;
+};
+
+/*
+ * ad7291 register access by I2C
+ */
+static int ad7291_i2c_read(struct ad7291_chip_info *chip, u8 reg, u16 *data)
+{
+       struct i2c_client *client = chip->client;
+       int ret = 0;
+
+       ret = i2c_smbus_read_word_data(client, reg);
+       if (ret < 0) {
+               dev_err(&client->dev, "I2C read error\n");
+               return ret;
+       }
+
+       *data = swab16((u16)ret);
+
+       return 0;
+}
+
+static int ad7291_i2c_write(struct ad7291_chip_info *chip, u8 reg, u16 data)
+{
+       struct i2c_client *client = chip->client;
+       int ret = 0;
+
+       ret = i2c_smbus_write_word_data(client, reg, swab16(data));
+       if (ret < 0)
+               dev_err(&client->dev, "I2C write error\n");
+
+       return ret;
+}
+
+/* Returns negative errno, or else the number of words read. */
+static int ad7291_i2c_read_data(struct ad7291_chip_info *chip, u8 reg, u16 *data)
+{
+       struct i2c_client *client = chip->client;
+       u8 commands[4];
+       int ret = 0;
+       int i, count;
+
+       if (reg == AD7291_T_SENSE || reg == AD7291_T_AVERAGE)
+               count = 2;
+       else if (reg == AD7291_VOLTAGE) {
+               if (!chip->channels) {
+                       dev_err(&client->dev, "No voltage channel is selected.\n");
+                       return -EINVAL;
+               }
+               count = 2 + chip->channels * 2;
+       } else {
+               dev_err(&client->dev, "I2C wrong data register\n");
+               return -EINVAL;
+       }
+
+       commands[0] = 0;
+       commands[1] = (chip->command >> 8) & 0xff;
+       commands[2] = chip->command & 0xff;
+       commands[3] = reg;
+
+       ret = i2c_master_send(client, commands, 4);
+       if (ret < 0) {
+               dev_err(&client->dev, "I2C master send error\n");
+               return ret;
+       }
+
+       ret = i2c_master_recv(client, (u8 *)data, count);
+       if (ret < 0) {
+               dev_err(&client->dev, "I2C master receive error\n");
+               return ret;
+       }
+       ret >>= 2;
+
+       for (i = 0; i < ret; i++)
+               data[i] = swab16(data[i]);
+
+       return ret;
+}
+
+static ssize_t ad7291_show_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7291_chip_info *chip = dev_info->dev_data;
+
+       if (chip->command & AD7291_AUTOCYCLE)
+               return sprintf(buf, "autocycle\n");
+       else
+               return sprintf(buf, "command\n");
+}
+
+static ssize_t ad7291_store_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7291_chip_info *chip = dev_info->dev_data;
+       u16 command;
+       int ret;
+
+       command = chip->command & (~AD7291_AUTOCYCLE);
+       if (strcmp(buf, "autocycle"))
+               command |= AD7291_AUTOCYCLE;
+
+       ret = ad7291_i2c_write(chip, AD7291_COMMAND, command);
+       if (ret)
+               return -EIO;
+
+       chip->command = command;
+
+       return ret;
+}
+
+static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+               ad7291_show_mode,
+               ad7291_store_mode,
+               0);
+
+static ssize_t ad7291_show_available_modes(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return sprintf(buf, "command\nautocycle\n");
+}
+
+static IIO_DEVICE_ATTR(available_modes, S_IRUGO, ad7291_show_available_modes, NULL, 0);
+
+static ssize_t ad7291_store_reset(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7291_chip_info *chip = dev_info->dev_data;
+       u16 command;
+       int ret;
+
+       command = chip->command | AD7291_RESET;
+
+       ret = ad7291_i2c_write(chip, AD7291_COMMAND, command);
+       if (ret)
+               return -EIO;
+
+       return ret;
+}
+
+static IIO_DEVICE_ATTR(reset, S_IWUSR,
+               NULL,
+               ad7291_store_reset,
+               0);
+
+static ssize_t ad7291_show_ext_ref(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7291_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", !!(chip->command & AD7291_EXT_REF));
+}
+
+static ssize_t ad7291_store_ext_ref(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7291_chip_info *chip = dev_info->dev_data;
+       u16 command;
+       int ret;
+
+       command = chip->command & (~AD7291_EXT_REF);
+       if (strcmp(buf, "1"))
+               command |= AD7291_EXT_REF;
+
+       ret = ad7291_i2c_write(chip, AD7291_COMMAND, command);
+       if (ret)
+               return -EIO;
+
+       chip->command = command;
+
+       return ret;
+}
+
+static IIO_DEVICE_ATTR(ext_ref, S_IRUGO | S_IWUSR,
+               ad7291_show_ext_ref,
+               ad7291_store_ext_ref,
+               0);
+
+static ssize_t ad7291_show_noise_delay(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7291_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", !!(chip->command & AD7291_NOISE_DELAY));
+}
+
+static ssize_t ad7291_store_noise_delay(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7291_chip_info *chip = dev_info->dev_data;
+       u16 command;
+       int ret;
+
+       command = chip->command & (~AD7291_NOISE_DELAY);
+       if (strcmp(buf, "1"))
+               command |= AD7291_NOISE_DELAY;
+
+       ret = ad7291_i2c_write(chip, AD7291_COMMAND, command);
+       if (ret)
+               return -EIO;
+
+       chip->command = command;
+
+       return ret;
+}
+
+static IIO_DEVICE_ATTR(noise_delay, S_IRUGO | S_IWUSR,
+               ad7291_show_noise_delay,
+               ad7291_store_noise_delay,
+               0);
+
+static ssize_t ad7291_show_t_sense(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7291_chip_info *chip = dev_info->dev_data;
+       u16 data;
+       char sign = ' ';
+       int ret;
+
+       ret = ad7291_i2c_read_data(chip, AD7291_T_SENSE, &data);
+       if (ret)
+               return -EIO;
+
+       if (data & AD7291_T_VALUE_SIGN) {
+               /* convert supplement to positive value */
+               data = (AD7291_T_VALUE_SIGN << 1) - data;
+               sign = '-';
+       }
+
+       return sprintf(buf, "%c%d.%.2d\n", sign,
+               (data >> AD7291_T_VALUE_FLOAT_OFFSET),
+               (data & AD7291_T_VALUE_FLOAT_MASK) * 25);
+}
+
+static IIO_DEVICE_ATTR(t_sense, S_IRUGO, ad7291_show_t_sense, NULL, 0);
+
+static ssize_t ad7291_show_t_average(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7291_chip_info *chip = dev_info->dev_data;
+       u16 data;
+       char sign = ' ';
+       int ret;
+
+       ret = ad7291_i2c_read_data(chip, AD7291_T_AVERAGE, &data);
+       if (ret)
+               return -EIO;
+
+       if (data & AD7291_T_VALUE_SIGN) {
+               /* convert supplement to positive value */
+               data = (AD7291_T_VALUE_SIGN << 1) - data;
+               sign = '-';
+       }
+
+       return sprintf(buf, "%c%d.%.2d\n", sign,
+               (data >> AD7291_T_VALUE_FLOAT_OFFSET),
+               (data & AD7291_T_VALUE_FLOAT_MASK) * 25);
+}
+
+static IIO_DEVICE_ATTR(t_average, S_IRUGO, ad7291_show_t_average, NULL, 0);
+
+static ssize_t ad7291_show_voltage(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7291_chip_info *chip = dev_info->dev_data;
+       u16 data[AD7291_VOLTAGE_LIMIT_COUNT];
+       int i, size, ret;
+
+       ret = ad7291_i2c_read_data(chip, AD7291_VOLTAGE, data);
+       if (ret)
+               return -EIO;
+
+       for (i = 0; i < AD7291_VOLTAGE_LIMIT_COUNT; i++) {
+               if (chip->command & (AD7291_T_SENSE_MASK << i)) {
+                       ret = sprintf(buf, "channel[%d]=%d\n", i,
+                                       data[i] & AD7291_VALUE_MASK);
+                       if (ret < 0)
+                               break;
+                       buf += ret;
+                       size += ret;
+               }
+       }
+
+       return size;
+}
+
+static IIO_DEVICE_ATTR(voltage, S_IRUGO, ad7291_show_voltage, NULL, 0);
+
+static ssize_t ad7291_show_channel_mask(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7291_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "0x%x\n", (chip->command & AD7291_VOLTAGE_MASK) >>
+                       AD7291_VOLTAGE_OFFSET);
+}
+
+static ssize_t ad7291_store_channel_mask(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7291_chip_info *chip = dev_info->dev_data;
+       u16 command;
+       unsigned long data;
+       int i, ret;
+
+       ret = strict_strtoul(buf, 16, &data);
+       if (ret || data > 0xff)
+               return -EINVAL;
+
+       command = chip->command & (~AD7291_VOLTAGE_MASK);
+       command |= data << AD7291_VOLTAGE_OFFSET;
+
+       ret = ad7291_i2c_write(chip, AD7291_COMMAND, command);
+       if (ret)
+               return -EIO;
+
+       chip->command = command;
+
+       for (i = 0, chip->channels = 0; i < AD7291_VOLTAGE_LIMIT_COUNT; i++) {
+               if (chip->command & (AD7291_T_SENSE_MASK << i))
+                       chip->channels++;
+       }
+
+       return ret;
+}
+
+static IIO_DEVICE_ATTR(channel_mask, S_IRUGO | S_IWUSR,
+               ad7291_show_channel_mask,
+               ad7291_store_channel_mask,
+               0);
+
+static ssize_t ad7291_show_name(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7291_chip_info *chip = dev_info->dev_data;
+       return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad7291_show_name, NULL, 0);
+
+static struct attribute *ad7291_attributes[] = {
+       &iio_dev_attr_available_modes.dev_attr.attr,
+       &iio_dev_attr_mode.dev_attr.attr,
+       &iio_dev_attr_reset.dev_attr.attr,
+       &iio_dev_attr_ext_ref.dev_attr.attr,
+       &iio_dev_attr_noise_delay.dev_attr.attr,
+       &iio_dev_attr_t_sense.dev_attr.attr,
+       &iio_dev_attr_t_average.dev_attr.attr,
+       &iio_dev_attr_voltage.dev_attr.attr,
+       &iio_dev_attr_channel_mask.dev_attr.attr,
+       &iio_dev_attr_name.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ad7291_attribute_group = {
+       .attrs = ad7291_attributes,
+};
+
+/*
+ * temperature bound events
+ */
+
+#define IIO_EVENT_CODE_AD7291_T_SENSE_HIGH  IIO_BUFFER_EVENT_CODE(0)
+#define IIO_EVENT_CODE_AD7291_T_SENSE_LOW   IIO_BUFFER_EVENT_CODE(1)
+#define IIO_EVENT_CODE_AD7291_T_AVG_HIGH    IIO_BUFFER_EVENT_CODE(2)
+#define IIO_EVENT_CODE_AD7291_T_AVG_LOW     IIO_BUFFER_EVENT_CODE(3)
+#define IIO_EVENT_CODE_AD7291_VOLTAGE_BASE  IIO_BUFFER_EVENT_CODE(4)
+
+static void ad7291_interrupt_bh(struct work_struct *work_s)
+{
+       struct ad7291_chip_info *chip =
+               container_of(work_s, struct ad7291_chip_info, thresh_work);
+       u16 t_status, v_status;
+       u16 command;
+       int i;
+
+       if (ad7291_i2c_read(chip, AD7291_T_ALERT_STATUS, &t_status))
+               return;
+
+       if (ad7291_i2c_read(chip, AD7291_VOLTAGE_ALERT_STATUS, &v_status))
+               return;
+
+       if (!(t_status || v_status))
+               return;
+
+       command = chip->command | AD7291_ALART_CLEAR;
+       ad7291_i2c_write(chip, AD7291_COMMAND, command);
+
+       command = chip->command & ~AD7291_ALART_CLEAR;
+       ad7291_i2c_write(chip, AD7291_COMMAND, command);
+
+       enable_irq(chip->client->irq);
+
+       for (i = 0; i < 4; i++) {
+               if (t_status & (1 << i))
+                       iio_push_event(chip->indio_dev, 0,
+                               IIO_EVENT_CODE_AD7291_T_SENSE_HIGH + i,
+                               chip->last_timestamp);
+       }
+
+       for (i = 0; i < AD7291_VOLTAGE_LIMIT_COUNT*2; i++) {
+               if (v_status & (1 << i))
+                       iio_push_event(chip->indio_dev, 0,
+                               IIO_EVENT_CODE_AD7291_VOLTAGE_BASE + i,
+                               chip->last_timestamp);
+       }
+}
+
+static int ad7291_interrupt(struct iio_dev *dev_info,
+               int index,
+               s64 timestamp,
+               int no_test)
+{
+       struct ad7291_chip_info *chip = dev_info->dev_data;
+
+       chip->last_timestamp = timestamp;
+       schedule_work(&chip->thresh_work);
+
+       return 0;
+}
+
+IIO_EVENT_SH(ad7291, &ad7291_interrupt);
+
+static inline ssize_t ad7291_show_t_bound(struct device *dev,
+               struct device_attribute *attr,
+               u8 bound_reg,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7291_chip_info *chip = dev_info->dev_data;
+       u16 data;
+       char sign = ' ';
+       int ret;
+
+       ret = ad7291_i2c_read(chip, bound_reg, &data);
+       if (ret)
+               return -EIO;
+
+       data &= AD7291_VALUE_MASK;
+       if (data & AD7291_T_VALUE_SIGN) {
+               /* convert supplement to positive value */
+               data = (AD7291_T_VALUE_SIGN << 1) - data;
+               sign = '-';
+       }
+
+       return sprintf(buf, "%c%d.%.2d\n", sign,
+                       data >> AD7291_T_VALUE_FLOAT_OFFSET,
+                       (data & AD7291_T_VALUE_FLOAT_MASK) * 25);
+}
+
+static inline ssize_t ad7291_set_t_bound(struct device *dev,
+               struct device_attribute *attr,
+               u8 bound_reg,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7291_chip_info *chip = dev_info->dev_data;
+       long tmp1, tmp2;
+       u16 data;
+       char *pos;
+       int ret;
+
+       pos = strchr(buf, '.');
+
+       ret = strict_strtol(buf, 10, &tmp1);
+
+       if (ret || tmp1 > 127 || tmp1 < -128)
+               return -EINVAL;
+
+       if (pos) {
+               len = strlen(pos);
+               if (len > AD7291_T_VALUE_FLOAT_OFFSET)
+                       len = AD7291_T_VALUE_FLOAT_OFFSET;
+               pos[len] = 0;
+               ret = strict_strtol(pos, 10, &tmp2);
+
+               if (!ret)
+                       tmp2 = (tmp2 / 25) * 25;
+       }
+
+       if (tmp1 < 0)
+               data = (u16)(-tmp1);
+       else
+               data = (u16)tmp1;
+       data = (data << AD7291_T_VALUE_FLOAT_OFFSET) |
+               (tmp2 & AD7291_T_VALUE_FLOAT_MASK);
+       if (tmp1 < 0)
+               /* convert positive value to supplyment */
+               data = (AD7291_T_VALUE_SIGN << 1) - data;
+
+       ret = ad7291_i2c_write(chip, bound_reg, data);
+       if (ret)
+               return -EIO;
+
+       return ret;
+}
+
+static ssize_t ad7291_show_t_sense_high(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return ad7291_show_t_bound(dev, attr,
+                       AD7291_T_SENSE_HIGH, buf);
+}
+
+static inline ssize_t ad7291_set_t_sense_high(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return ad7291_set_t_bound(dev, attr,
+                       AD7291_T_SENSE_HIGH, buf, len);
+}
+
+static ssize_t ad7291_show_t_sense_low(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return ad7291_show_t_bound(dev, attr,
+                       AD7291_T_SENSE_LOW, buf);
+}
+
+static inline ssize_t ad7291_set_t_sense_low(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return ad7291_set_t_bound(dev, attr,
+                       AD7291_T_SENSE_LOW, buf, len);
+}
+
+static ssize_t ad7291_show_t_sense_hyst(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return ad7291_show_t_bound(dev, attr,
+                       AD7291_T_SENSE_HYST, buf);
+}
+
+static inline ssize_t ad7291_set_t_sense_hyst(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return ad7291_set_t_bound(dev, attr,
+                       AD7291_T_SENSE_HYST, buf, len);
+}
+
+static inline ssize_t ad7291_show_v_bound(struct device *dev,
+               struct device_attribute *attr,
+               u8 bound_reg,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7291_chip_info *chip = dev_info->dev_data;
+       u16 data;
+       int ret;
+
+       if (bound_reg < AD7291_VOLTAGE_LIMIT_BASE ||
+               bound_reg >= AD7291_VOLTAGE_LIMIT_BASE +
+               AD7291_VOLTAGE_LIMIT_COUNT)
+               return -EINVAL;
+
+       ret = ad7291_i2c_read(chip, bound_reg, &data);
+       if (ret)
+               return -EIO;
+
+       data &= AD7291_VALUE_MASK;
+
+       return sprintf(buf, "%d\n", data);
+}
+
+static inline ssize_t ad7291_set_v_bound(struct device *dev,
+               struct device_attribute *attr,
+               u8 bound_reg,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7291_chip_info *chip = dev_info->dev_data;
+       unsigned long value;
+       u16 data;
+       int ret;
+
+       if (bound_reg < AD7291_VOLTAGE_LIMIT_BASE ||
+               bound_reg >= AD7291_VOLTAGE_LIMIT_BASE +
+               AD7291_VOLTAGE_LIMIT_COUNT)
+               return -EINVAL;
+
+       ret = strict_strtoul(buf, 10, &value);
+
+       if (ret || value >= 4096)
+               return -EINVAL;
+
+       data = (u16)value;
+       ret = ad7291_i2c_write(chip, bound_reg, data);
+       if (ret)
+               return -EIO;
+
+       return ret;
+}
+
+static int ad7291_get_voltage_limit_regs(const char *channel)
+{
+       int index;
+
+       if (strlen(channel) < 3 && channel[0] != 'v')
+               return -EINVAL;
+
+       index = channel[1] - '0';
+       if (index >= AD7291_VOLTAGE_LIMIT_COUNT)
+               return -EINVAL;
+
+       return index;
+}
+
+static ssize_t ad7291_show_voltage_high(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int regs;
+
+       regs = ad7291_get_voltage_limit_regs(attr->attr.name);
+
+       if (regs < 0)
+               return regs;
+
+       return ad7291_show_t_bound(dev, attr, regs, buf);
+}
+
+static inline ssize_t ad7291_set_voltage_high(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       int regs;
+
+       regs = ad7291_get_voltage_limit_regs(attr->attr.name);
+
+       if (regs < 0)
+               return regs;
+
+       return ad7291_set_t_bound(dev, attr, regs, buf, len);
+}
+
+static ssize_t ad7291_show_voltage_low(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int regs;
+
+       regs = ad7291_get_voltage_limit_regs(attr->attr.name);
+
+       if (regs < 0)
+               return regs;
+
+       return ad7291_show_t_bound(dev, attr, regs+1, buf);
+}
+
+static inline ssize_t ad7291_set_voltage_low(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       int regs;
+
+       regs = ad7291_get_voltage_limit_regs(attr->attr.name);
+
+       if (regs < 0)
+               return regs;
+
+       return ad7291_set_t_bound(dev, attr, regs+1, buf, len);
+}
+
+static ssize_t ad7291_show_voltage_hyst(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int regs;
+
+       regs = ad7291_get_voltage_limit_regs(attr->attr.name);
+
+       if (regs < 0)
+               return regs;
+
+       return ad7291_show_t_bound(dev, attr, regs+2, buf);
+}
+
+static inline ssize_t ad7291_set_voltage_hyst(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       int regs;
+
+       regs = ad7291_get_voltage_limit_regs(attr->attr.name);
+
+       if (regs < 0)
+               return regs;
+
+       return ad7291_set_t_bound(dev, attr, regs+2, buf, len);
+}
+
+IIO_EVENT_ATTR_SH(t_sense_high, iio_event_ad7291,
+               ad7291_show_t_sense_high, ad7291_set_t_sense_high, 0);
+IIO_EVENT_ATTR_SH(t_sense_low, iio_event_ad7291,
+               ad7291_show_t_sense_low, ad7291_set_t_sense_low, 0);
+IIO_EVENT_ATTR_SH(t_sense_hyst, iio_event_ad7291,
+               ad7291_show_t_sense_hyst, ad7291_set_t_sense_hyst, 0);
+
+IIO_EVENT_ATTR_SH(v0_high, iio_event_ad7291,
+               ad7291_show_voltage_high, ad7291_set_voltage_high, 0);
+IIO_EVENT_ATTR_SH(v0_low, iio_event_ad7291,
+               ad7291_show_voltage_low, ad7291_set_voltage_low, 0);
+IIO_EVENT_ATTR_SH(v0_hyst, iio_event_ad7291,
+               ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0);
+IIO_EVENT_ATTR_SH(v1_high, iio_event_ad7291,
+               ad7291_show_voltage_high, ad7291_set_voltage_high, 0);
+IIO_EVENT_ATTR_SH(v1_low, iio_event_ad7291,
+               ad7291_show_voltage_low, ad7291_set_voltage_low, 0);
+IIO_EVENT_ATTR_SH(v1_hyst, iio_event_ad7291,
+               ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0);
+IIO_EVENT_ATTR_SH(v2_high, iio_event_ad7291,
+               ad7291_show_voltage_high, ad7291_set_voltage_high, 0);
+IIO_EVENT_ATTR_SH(v2_low, iio_event_ad7291,
+               ad7291_show_voltage_low, ad7291_set_voltage_low, 0);
+IIO_EVENT_ATTR_SH(v2_hyst, iio_event_ad7291,
+               ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0);
+IIO_EVENT_ATTR_SH(v3_high, iio_event_ad7291,
+               ad7291_show_voltage_high, ad7291_set_voltage_high, 0);
+IIO_EVENT_ATTR_SH(v3_low, iio_event_ad7291,
+               ad7291_show_voltage_low, ad7291_set_voltage_low, 0);
+IIO_EVENT_ATTR_SH(v3_hyst, iio_event_ad7291,
+               ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0);
+IIO_EVENT_ATTR_SH(v4_high, iio_event_ad7291,
+               ad7291_show_voltage_high, ad7291_set_voltage_high, 0);
+IIO_EVENT_ATTR_SH(v4_low, iio_event_ad7291,
+               ad7291_show_voltage_low, ad7291_set_voltage_low, 0);
+IIO_EVENT_ATTR_SH(v4_hyst, iio_event_ad7291,
+               ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0);
+IIO_EVENT_ATTR_SH(v5_high, iio_event_ad7291,
+               ad7291_show_voltage_high, ad7291_set_voltage_high, 0);
+IIO_EVENT_ATTR_SH(v5_low, iio_event_ad7291,
+               ad7291_show_voltage_low, ad7291_set_voltage_low, 0);
+IIO_EVENT_ATTR_SH(v5_hyst, iio_event_ad7291,
+               ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0);
+IIO_EVENT_ATTR_SH(v6_high, iio_event_ad7291,
+               ad7291_show_voltage_high, ad7291_set_voltage_high, 0);
+IIO_EVENT_ATTR_SH(v6_low, iio_event_ad7291,
+               ad7291_show_voltage_low, ad7291_set_voltage_low, 0);
+IIO_EVENT_ATTR_SH(v6_hyst, iio_event_ad7291,
+               ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0);
+IIO_EVENT_ATTR_SH(v7_high, iio_event_ad7291,
+               ad7291_show_voltage_high, ad7291_set_voltage_high, 0);
+IIO_EVENT_ATTR_SH(v7_low, iio_event_ad7291,
+               ad7291_show_voltage_low, ad7291_set_voltage_low, 0);
+IIO_EVENT_ATTR_SH(v7_hyst, iio_event_ad7291,
+               ad7291_show_voltage_hyst, ad7291_set_voltage_hyst, 0);
+
+static struct attribute *ad7291_event_attributes[] = {
+       &iio_event_attr_t_sense_high.dev_attr.attr,
+       &iio_event_attr_t_sense_low.dev_attr.attr,
+       &iio_event_attr_t_sense_hyst.dev_attr.attr,
+       &iio_event_attr_v0_high.dev_attr.attr,
+       &iio_event_attr_v0_low.dev_attr.attr,
+       &iio_event_attr_v0_hyst.dev_attr.attr,
+       &iio_event_attr_v1_high.dev_attr.attr,
+       &iio_event_attr_v1_low.dev_attr.attr,
+       &iio_event_attr_v1_hyst.dev_attr.attr,
+       &iio_event_attr_v2_high.dev_attr.attr,
+       &iio_event_attr_v2_low.dev_attr.attr,
+       &iio_event_attr_v2_hyst.dev_attr.attr,
+       &iio_event_attr_v3_high.dev_attr.attr,
+       &iio_event_attr_v3_low.dev_attr.attr,
+       &iio_event_attr_v3_hyst.dev_attr.attr,
+       &iio_event_attr_v4_high.dev_attr.attr,
+       &iio_event_attr_v4_low.dev_attr.attr,
+       &iio_event_attr_v4_hyst.dev_attr.attr,
+       &iio_event_attr_v5_high.dev_attr.attr,
+       &iio_event_attr_v5_low.dev_attr.attr,
+       &iio_event_attr_v5_hyst.dev_attr.attr,
+       &iio_event_attr_v6_high.dev_attr.attr,
+       &iio_event_attr_v6_low.dev_attr.attr,
+       &iio_event_attr_v6_hyst.dev_attr.attr,
+       &iio_event_attr_v7_high.dev_attr.attr,
+       &iio_event_attr_v7_low.dev_attr.attr,
+       &iio_event_attr_v7_hyst.dev_attr.attr,
+       NULL,
+};
+
+static struct attribute_group ad7291_event_attribute_group = {
+       .attrs = ad7291_event_attributes,
+};
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit ad7291_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct ad7291_chip_info *chip;
+       int ret = 0;
+
+       chip = kzalloc(sizeof(struct ad7291_chip_info), GFP_KERNEL);
+
+       if (chip == NULL)
+               return -ENOMEM;
+
+       /* this is only used for device removal purposes */
+       i2c_set_clientdata(client, chip);
+
+       chip->client = client;
+       chip->name = id->name;
+       chip->command = AD7291_NOISE_DELAY | AD7291_T_SENSE_MASK;
+
+       chip->indio_dev = iio_allocate_device();
+       if (chip->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_chip;
+       }
+
+       chip->indio_dev->dev.parent = &client->dev;
+       chip->indio_dev->attrs = &ad7291_attribute_group;
+       chip->indio_dev->event_attrs = &ad7291_event_attribute_group;
+       chip->indio_dev->dev_data = (void *)chip;
+       chip->indio_dev->driver_module = THIS_MODULE;
+       chip->indio_dev->num_interrupt_lines = 1;
+       chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(chip->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       if (client->irq > 0) {
+               ret = iio_register_interrupt_line(client->irq,
+                               chip->indio_dev,
+                               0,
+                               IRQF_TRIGGER_LOW,
+                               chip->name);
+               if (ret)
+                       goto error_unreg_dev;
+
+               /*
+                * The event handler list element refer to iio_event_ad7291.
+                * All event attributes bind to the same event handler.
+                * So, only register event handler once.
+                */
+               iio_add_event_to_list(&iio_event_ad7291,
+                               &chip->indio_dev->interrupts[0]->ev_list);
+
+               INIT_WORK(&chip->thresh_work, ad7291_interrupt_bh);
+
+               /* set irq polarity low level */
+               chip->command |= AD7291_ALART_POLARITY;
+       }
+
+       ret = ad7291_i2c_write(chip, AD7291_COMMAND, chip->command);
+       if (ret) {
+               ret = -EIO;
+               goto error_unreg_irq;
+       }
+
+       dev_info(&client->dev, "%s temperature sensor registered.\n",
+                        id->name);
+
+       return 0;
+
+error_unreg_irq:
+       iio_unregister_interrupt_line(chip->indio_dev, 0);
+error_unreg_dev:
+       iio_device_unregister(chip->indio_dev);
+error_free_dev:
+       iio_free_device(chip->indio_dev);
+error_free_chip:
+       kfree(chip);
+
+       return ret;
+}
+
+static int __devexit ad7291_remove(struct i2c_client *client)
+{
+       struct ad7291_chip_info *chip = i2c_get_clientdata(client);
+       struct iio_dev *indio_dev = chip->indio_dev;
+
+       if (client->irq)
+               iio_unregister_interrupt_line(indio_dev, 0);
+       iio_device_unregister(indio_dev);
+       iio_free_device(chip->indio_dev);
+       kfree(chip);
+
+       return 0;
+}
+
+static const struct i2c_device_id ad7291_id[] = {
+       { "ad7291", 0 },
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, ad7291_id);
+
+static struct i2c_driver ad7291_driver = {
+       .driver = {
+               .name = "ad7291",
+       },
+       .probe = ad7291_probe,
+       .remove = __devexit_p(ad7291_remove),
+       .id_table = ad7291_id,
+};
+
+static __init int ad7291_init(void)
+{
+       return i2c_add_driver(&ad7291_driver);
+}
+
+static __exit void ad7291_exit(void)
+{
+       i2c_del_driver(&ad7291_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD7291 digital"
+                       " temperature sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(ad7291_init);
+module_exit(ad7291_exit);
diff --git a/drivers/staging/iio/adc/ad7298.c b/drivers/staging/iio/adc/ad7298.c
new file mode 100644 (file)
index 0000000..1a080c9
--- /dev/null
@@ -0,0 +1,501 @@
+/*
+ * AD7298 digital temperature sensor driver supporting AD7298
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * AD7298 command
+ */
+#define AD7298_PD                      0x1
+#define AD7298_T_AVG_MASK              0x2
+#define AD7298_EXT_REF                 0x4
+#define AD7298_T_SENSE_MASK            0x20
+#define AD7298_VOLTAGE_MASK            0x3fc0
+#define AD7298_VOLTAGE_OFFSET          0x6
+#define AD7298_VOLTAGE_LIMIT_COUNT     8
+#define AD7298_REPEAT                  0x40
+#define AD7298_WRITE                   0x80
+
+/*
+ * AD7298 value masks
+ */
+#define AD7298_CHANNEL_MASK            0xf000
+#define AD7298_VALUE_MASK              0xfff
+#define AD7298_T_VALUE_SIGN            0x400
+#define AD7298_T_VALUE_FLOAT_OFFSET    2
+#define AD7298_T_VALUE_FLOAT_MASK      0x2
+
+/*
+ * struct ad7298_chip_info - chip specifc information
+ */
+
+struct ad7298_chip_info {
+       const char *name;
+       struct spi_device *spi_dev;
+       struct iio_dev *indio_dev;
+       u16 command;
+       u16 busy_pin;
+       u8  channels;   /* Active voltage channels */
+};
+
+/*
+ * ad7298 register access by SPI
+ */
+static int ad7298_spi_write(struct ad7298_chip_info *chip, u16 data)
+{
+       struct spi_device *spi_dev = chip->spi_dev;
+       int ret = 0;
+
+       data |= AD7298_WRITE;
+       data = cpu_to_be16(data);
+       ret = spi_write(spi_dev, (u8 *)&data, sizeof(data));
+       if (ret < 0)
+               dev_err(&spi_dev->dev, "SPI write error\n");
+
+       return ret;
+}
+
+static int ad7298_spi_read(struct ad7298_chip_info *chip, u16 mask, u16 *data)
+{
+       struct spi_device *spi_dev = chip->spi_dev;
+       int ret = 0;
+       u8 count = chip->channels;
+       u16 command;
+       int i;
+
+       if (mask & AD7298_T_SENSE_MASK) {
+               command = chip->command & ~(AD7298_T_AVG_MASK | AD7298_VOLTAGE_MASK);
+               command |= AD7298_T_SENSE_MASK;
+               count = 1;
+       } else if (mask & AD7298_T_AVG_MASK) {
+               command = chip->command & ~AD7298_VOLTAGE_MASK;
+               command |= AD7298_T_SENSE_MASK | AD7298_T_AVG_MASK;
+               count = 2;
+       } else if (mask & AD7298_VOLTAGE_MASK) {
+               command = chip->command & ~(AD7298_T_AVG_MASK | AD7298_T_SENSE_MASK);
+               count = chip->channels;
+       }
+
+       ret = ad7298_spi_write(chip, chip->command);
+       if (ret < 0) {
+               dev_err(&spi_dev->dev, "SPI write command error\n");
+               return ret;
+       }
+
+       ret = spi_read(spi_dev, (u8 *)&command, sizeof(command));
+       if (ret < 0) {
+               dev_err(&spi_dev->dev, "SPI read error\n");
+               return ret;
+       }
+
+       i = 10000;
+       while (i && gpio_get_value(chip->busy_pin)) {
+               cpu_relax();
+               i--;
+       }
+       if (!i) {
+               dev_err(&spi_dev->dev, "Always in busy convertion.\n");
+               return -EBUSY;
+       }
+
+       for (i = 0; i < count; i++) {
+               ret = spi_read(spi_dev, (u8 *)&data[i], sizeof(data[i]));
+               if (ret < 0) {
+                       dev_err(&spi_dev->dev, "SPI read error\n");
+                       return ret;
+               }
+               *data = be16_to_cpu(data[i]);
+       }
+
+       return 0;
+}
+
+static ssize_t ad7298_show_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7298_chip_info *chip = dev_info->dev_data;
+
+       if (chip->command & AD7298_REPEAT)
+               return sprintf(buf, "repeat\n");
+       else
+               return sprintf(buf, "normal\n");
+}
+
+static ssize_t ad7298_store_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7298_chip_info *chip = dev_info->dev_data;
+
+       if (strcmp(buf, "repeat"))
+               chip->command |= AD7298_REPEAT;
+       else
+               chip->command &= (~AD7298_REPEAT);
+
+       return 1;
+}
+
+static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+               ad7298_show_mode,
+               ad7298_store_mode,
+               0);
+
+static ssize_t ad7298_show_available_modes(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return sprintf(buf, "normal\nrepeat\n");
+}
+
+static IIO_DEVICE_ATTR(available_modes, S_IRUGO, ad7298_show_available_modes, NULL, 0);
+
+static ssize_t ad7298_store_reset(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7298_chip_info *chip = dev_info->dev_data;
+       u16 command;
+       int ret;
+
+       command = chip->command & ~AD7298_PD;
+
+       ret = ad7298_spi_write(chip, command);
+       if (ret)
+               return -EIO;
+
+       command = chip->command | AD7298_PD;
+
+       ret = ad7298_spi_write(chip, command);
+       if (ret)
+               return -EIO;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(reset, S_IWUSR,
+               NULL,
+               ad7298_store_reset,
+               0);
+
+static ssize_t ad7298_show_ext_ref(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7298_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", !!(chip->command & AD7298_EXT_REF));
+}
+
+static ssize_t ad7298_store_ext_ref(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7298_chip_info *chip = dev_info->dev_data;
+       u16 command;
+       int ret;
+
+       command = chip->command & (~AD7298_EXT_REF);
+       if (strcmp(buf, "1"))
+               command |= AD7298_EXT_REF;
+
+       ret = ad7298_spi_write(chip, command);
+       if (ret)
+               return -EIO;
+
+       chip->command = command;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(ext_ref, S_IRUGO | S_IWUSR,
+               ad7298_show_ext_ref,
+               ad7298_store_ext_ref,
+               0);
+
+static ssize_t ad7298_show_t_sense(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7298_chip_info *chip = dev_info->dev_data;
+       u16 data;
+       char sign = ' ';
+       int ret;
+
+       ret = ad7298_spi_read(chip, AD7298_T_SENSE_MASK, &data);
+       if (ret)
+               return -EIO;
+
+       if (data & AD7298_T_VALUE_SIGN) {
+               /* convert supplement to positive value */
+               data = (AD7298_T_VALUE_SIGN << 1) - data;
+               sign = '-';
+       }
+
+       return sprintf(buf, "%c%d.%.2d\n", sign,
+               (data >> AD7298_T_VALUE_FLOAT_OFFSET),
+               (data & AD7298_T_VALUE_FLOAT_MASK) * 25);
+}
+
+static IIO_DEVICE_ATTR(t_sense, S_IRUGO, ad7298_show_t_sense, NULL, 0);
+
+static ssize_t ad7298_show_t_average(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7298_chip_info *chip = dev_info->dev_data;
+       u16 data[2];
+       char sign = ' ';
+       int ret;
+
+       ret = ad7298_spi_read(chip, AD7298_T_AVG_MASK, data);
+       if (ret)
+               return -EIO;
+
+       if (data[1] & AD7298_T_VALUE_SIGN) {
+               /* convert supplement to positive value */
+               data[1] = (AD7298_T_VALUE_SIGN << 1) - data[1];
+               sign = '-';
+       }
+
+       return sprintf(buf, "%c%d.%.2d\n", sign,
+               (data[1] >> AD7298_T_VALUE_FLOAT_OFFSET),
+               (data[1] & AD7298_T_VALUE_FLOAT_MASK) * 25);
+}
+
+static IIO_DEVICE_ATTR(t_average, S_IRUGO, ad7298_show_t_average, NULL, 0);
+
+static ssize_t ad7298_show_voltage(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7298_chip_info *chip = dev_info->dev_data;
+       u16 data[AD7298_VOLTAGE_LIMIT_COUNT];
+       int i, size, ret;
+
+       ret = ad7298_spi_read(chip, AD7298_VOLTAGE_MASK, data);
+       if (ret)
+               return -EIO;
+
+       for (i = 0; i < AD7298_VOLTAGE_LIMIT_COUNT; i++) {
+               if (chip->command & (AD7298_T_SENSE_MASK << i)) {
+                       ret = sprintf(buf, "channel[%d]=%d\n", i,
+                                       data[i] & AD7298_VALUE_MASK);
+                       if (ret < 0)
+                               break;
+                       buf += ret;
+                       size += ret;
+               }
+       }
+
+       return size;
+}
+
+static IIO_DEVICE_ATTR(voltage, S_IRUGO, ad7298_show_voltage, NULL, 0);
+
+static ssize_t ad7298_show_channel_mask(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7298_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "0x%x\n", (chip->command & AD7298_VOLTAGE_MASK) >>
+                       AD7298_VOLTAGE_OFFSET);
+}
+
+static ssize_t ad7298_store_channel_mask(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7298_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int i, ret;
+
+       ret = strict_strtoul(buf, 16, &data);
+       if (ret || data > 0xff)
+               return -EINVAL;
+
+       chip->command &= (~AD7298_VOLTAGE_MASK);
+       chip->command |= data << AD7298_VOLTAGE_OFFSET;
+
+       for (i = 0, chip->channels = 0; i < AD7298_VOLTAGE_LIMIT_COUNT; i++) {
+               if (chip->command & (AD7298_T_SENSE_MASK << i))
+                       chip->channels++;
+       }
+
+       return ret;
+}
+
+static IIO_DEVICE_ATTR(channel_mask, S_IRUGO | S_IWUSR,
+               ad7298_show_channel_mask,
+               ad7298_store_channel_mask,
+               0);
+
+static ssize_t ad7298_show_name(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7298_chip_info *chip = dev_info->dev_data;
+       return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad7298_show_name, NULL, 0);
+
+static struct attribute *ad7298_attributes[] = {
+       &iio_dev_attr_available_modes.dev_attr.attr,
+       &iio_dev_attr_mode.dev_attr.attr,
+       &iio_dev_attr_reset.dev_attr.attr,
+       &iio_dev_attr_ext_ref.dev_attr.attr,
+       &iio_dev_attr_t_sense.dev_attr.attr,
+       &iio_dev_attr_t_average.dev_attr.attr,
+       &iio_dev_attr_voltage.dev_attr.attr,
+       &iio_dev_attr_channel_mask.dev_attr.attr,
+       &iio_dev_attr_name.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ad7298_attribute_group = {
+       .attrs = ad7298_attributes,
+};
+
+/*
+ * device probe and remove
+ */
+static int __devinit ad7298_probe(struct spi_device *spi_dev)
+{
+       struct ad7298_chip_info *chip;
+       unsigned short *pins = spi_dev->dev.platform_data;
+       int ret = 0;
+
+       chip = kzalloc(sizeof(struct ad7298_chip_info), GFP_KERNEL);
+
+       if (chip == NULL)
+               return -ENOMEM;
+
+       /* this is only used for device removal purposes */
+       dev_set_drvdata(&spi_dev->dev, chip);
+
+       chip->spi_dev = spi_dev;
+       chip->name = spi_dev->modalias;
+       chip->busy_pin = pins[0];
+
+       ret = gpio_request(chip->busy_pin, chip->name);
+       if (ret) {
+               dev_err(&spi_dev->dev, "Fail to request busy gpio PIN %d.\n",
+                       chip->busy_pin);
+               goto error_free_chip;
+       }
+       gpio_direction_input(chip->busy_pin);
+
+       chip->indio_dev = iio_allocate_device();
+       if (chip->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_gpio;
+       }
+
+       chip->indio_dev->dev.parent = &spi_dev->dev;
+       chip->indio_dev->attrs = &ad7298_attribute_group;
+       chip->indio_dev->dev_data = (void *)chip;
+       chip->indio_dev->driver_module = THIS_MODULE;
+       chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(chip->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       dev_info(&spi_dev->dev, "%s temperature sensor and ADC registered.\n",
+                        chip->name);
+
+       return 0;
+
+error_free_dev:
+       iio_free_device(chip->indio_dev);
+error_free_gpio:
+       gpio_free(chip->busy_pin);
+error_free_chip:
+       kfree(chip);
+
+       return ret;
+}
+
+static int __devexit ad7298_remove(struct spi_device *spi_dev)
+{
+       struct ad7298_chip_info *chip = dev_get_drvdata(&spi_dev->dev);
+       struct iio_dev *indio_dev = chip->indio_dev;
+
+       dev_set_drvdata(&spi_dev->dev, NULL);
+       iio_device_unregister(indio_dev);
+       iio_free_device(chip->indio_dev);
+       gpio_free(chip->busy_pin);
+       kfree(chip);
+
+       return 0;
+}
+
+static const struct spi_device_id ad7298_id[] = {
+       { "ad7298", 0 },
+       {}
+};
+
+MODULE_DEVICE_TABLE(spi, ad7298_id);
+
+static struct spi_driver ad7298_driver = {
+       .driver = {
+               .name = "ad7298",
+               .bus = &spi_bus_type,
+               .owner = THIS_MODULE,
+       },
+       .probe = ad7298_probe,
+       .remove = __devexit_p(ad7298_remove),
+       .id_table = ad7298_id,
+};
+
+static __init int ad7298_init(void)
+{
+       return spi_register_driver(&ad7298_driver);
+}
+
+static __exit void ad7298_exit(void)
+{
+       spi_unregister_driver(&ad7298_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD7298 digital"
+                       " temperature sensor and ADC driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(ad7298_init);
+module_exit(ad7298_exit);
diff --git a/drivers/staging/iio/adc/ad7314.c b/drivers/staging/iio/adc/ad7314.c
new file mode 100644 (file)
index 0000000..8c17b1f
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * AD7314 digital temperature sensor driver for AD7314, ADT7301 and ADT7302
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * AD7314 power mode
+ */
+#define AD7314_PD              0x2000
+
+/*
+ * AD7314 temperature masks
+ */
+#define AD7314_TEMP_SIGN               0x200
+#define AD7314_TEMP_MASK               0x7FE0
+#define AD7314_TEMP_OFFSET             5
+#define AD7314_TEMP_FLOAT_OFFSET       2
+#define AD7314_TEMP_FLOAT_MASK         0x3
+
+/*
+ * ADT7301 and ADT7302 temperature masks
+ */
+#define ADT7301_TEMP_SIGN              0x2000
+#define ADT7301_TEMP_MASK              0x2FFF
+#define ADT7301_TEMP_FLOAT_OFFSET      5
+#define ADT7301_TEMP_FLOAT_MASK                0x1F
+
+/*
+ * struct ad7314_chip_info - chip specifc information
+ */
+
+struct ad7314_chip_info {
+       const char *name;
+       struct spi_device *spi_dev;
+       struct iio_dev *indio_dev;
+       s64 last_timestamp;
+       u8  mode;
+};
+
+/*
+ * ad7314 register access by SPI
+ */
+
+static int ad7314_spi_read(struct ad7314_chip_info *chip, u16 *data)
+{
+       struct spi_device *spi_dev = chip->spi_dev;
+       int ret = 0;
+       u16 value;
+
+       ret = spi_read(spi_dev, (u8 *)&value, sizeof(value));
+       if (ret < 0) {
+               dev_err(&spi_dev->dev, "SPI read error\n");
+               return ret;
+       }
+
+       *data = be16_to_cpu((u16)value);
+
+       return ret;
+}
+
+static int ad7314_spi_write(struct ad7314_chip_info *chip, u16 data)
+{
+       struct spi_device *spi_dev = chip->spi_dev;
+       int ret = 0;
+       u16 value = cpu_to_be16(data);
+
+       ret = spi_write(spi_dev, (u8 *)&value, sizeof(value));
+       if (ret < 0)
+               dev_err(&spi_dev->dev, "SPI write error\n");
+
+       return ret;
+}
+
+static ssize_t ad7314_show_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7314_chip_info *chip = dev_info->dev_data;
+
+       if (chip->mode)
+               return sprintf(buf, "power-save\n");
+       else
+               return sprintf(buf, "full\n");
+}
+
+static ssize_t ad7314_store_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7314_chip_info *chip = dev_info->dev_data;
+       u16 mode = 0;
+       int ret;
+
+       if (!strcmp(buf, "full"))
+               mode = AD7314_PD;
+
+       ret = ad7314_spi_write(chip, mode);
+       if (ret)
+               return -EIO;
+
+       chip->mode = mode;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+               ad7314_show_mode,
+               ad7314_store_mode,
+               0);
+
+static ssize_t ad7314_show_available_modes(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return sprintf(buf, "full\npower-save\n");
+}
+
+static IIO_DEVICE_ATTR(available_modes, S_IRUGO, ad7314_show_available_modes, NULL, 0);
+
+static ssize_t ad7314_show_temperature(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7314_chip_info *chip = dev_info->dev_data;
+       u16 data;
+       char sign = ' ';
+       int ret;
+
+       if (chip->mode) {
+               ret = ad7314_spi_write(chip, 0);
+               if (ret)
+                       return -EIO;
+       }
+
+       ret = ad7314_spi_read(chip, &data);
+       if (ret)
+               return -EIO;
+
+       if (chip->mode)
+               ad7314_spi_write(chip, chip->mode);
+
+       if (strcmp(chip->name, "ad7314")) {
+               data = (data & AD7314_TEMP_MASK) >>
+                       AD7314_TEMP_OFFSET;
+               if (data & AD7314_TEMP_SIGN) {
+                       data = (AD7314_TEMP_SIGN << 1) - data;
+                       sign = '-';
+               }
+
+               return sprintf(buf, "%c%d.%.2d\n", sign,
+                               data >> AD7314_TEMP_FLOAT_OFFSET,
+                               (data & AD7314_TEMP_FLOAT_MASK) * 25);
+       } else {
+               data &= ADT7301_TEMP_MASK;
+               if (data & ADT7301_TEMP_SIGN) {
+                       data = (ADT7301_TEMP_SIGN << 1) - data;
+                       sign = '-';
+               }
+
+               return sprintf(buf, "%c%d.%.5d\n", sign,
+                               data >> ADT7301_TEMP_FLOAT_OFFSET,
+                               (data & ADT7301_TEMP_FLOAT_MASK) * 3125);
+       }
+}
+
+static IIO_DEVICE_ATTR(temperature, S_IRUGO, ad7314_show_temperature, NULL, 0);
+
+static ssize_t ad7314_show_name(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7314_chip_info *chip = dev_info->dev_data;
+       return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad7314_show_name, NULL, 0);
+
+static struct attribute *ad7314_attributes[] = {
+       &iio_dev_attr_available_modes.dev_attr.attr,
+       &iio_dev_attr_mode.dev_attr.attr,
+       &iio_dev_attr_temperature.dev_attr.attr,
+       &iio_dev_attr_name.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ad7314_attribute_group = {
+       .attrs = ad7314_attributes,
+};
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit ad7314_probe(struct spi_device *spi_dev)
+{
+       struct ad7314_chip_info *chip;
+       int ret = 0;
+
+       chip = kzalloc(sizeof(struct ad7314_chip_info), GFP_KERNEL);
+
+       if (chip == NULL)
+               return -ENOMEM;
+
+       /* this is only used for device removal purposes */
+       dev_set_drvdata(&spi_dev->dev, chip);
+
+       chip->spi_dev = spi_dev;
+       chip->name = spi_dev->modalias;
+
+       chip->indio_dev = iio_allocate_device();
+       if (chip->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_chip;
+       }
+
+       chip->indio_dev->dev.parent = &spi_dev->dev;
+       chip->indio_dev->attrs = &ad7314_attribute_group;
+       chip->indio_dev->dev_data = (void *)chip;
+       chip->indio_dev->driver_module = THIS_MODULE;
+
+       ret = iio_device_register(chip->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       dev_info(&spi_dev->dev, "%s temperature sensor registered.\n",
+                        chip->name);
+
+       return 0;
+error_free_dev:
+       iio_free_device(chip->indio_dev);
+error_free_chip:
+       kfree(chip);
+
+       return ret;
+}
+
+static int __devexit ad7314_remove(struct spi_device *spi_dev)
+{
+       struct ad7314_chip_info *chip = dev_get_drvdata(&spi_dev->dev);
+       struct iio_dev *indio_dev = chip->indio_dev;
+
+       dev_set_drvdata(&spi_dev->dev, NULL);
+       if (spi_dev->irq)
+               iio_unregister_interrupt_line(indio_dev, 0);
+       iio_device_unregister(indio_dev);
+       iio_free_device(chip->indio_dev);
+       kfree(chip);
+
+       return 0;
+}
+
+static const struct spi_device_id ad7314_id[] = {
+       { "adt7301", 0 },
+       { "adt7302", 0 },
+       { "ad7314", 0 },
+       {}
+};
+
+static struct spi_driver ad7314_driver = {
+       .driver = {
+               .name = "ad7314",
+               .bus = &spi_bus_type,
+               .owner = THIS_MODULE,
+       },
+       .probe = ad7314_probe,
+       .remove = __devexit_p(ad7314_remove),
+       .id_table = ad7314_id,
+};
+
+static __init int ad7314_init(void)
+{
+       return spi_register_driver(&ad7314_driver);
+}
+
+static __exit void ad7314_exit(void)
+{
+       spi_unregister_driver(&ad7314_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital"
+                       " temperature sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(ad7314_init);
+module_exit(ad7314_exit);
diff --git a/drivers/staging/iio/adc/ad7745.c b/drivers/staging/iio/adc/ad7745.c
new file mode 100644 (file)
index 0000000..ab7ef84
--- /dev/null
@@ -0,0 +1,734 @@
+/*
+ * AD774X capacitive sensor driver supporting AD7745/6/7
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * AD774X registers definition
+ */
+
+#define AD774X_STATUS          0
+#define AD774X_STATUS_RDY      (1 << 2)
+#define AD774X_STATUS_RDYVT    (1 << 1)
+#define AD774X_STATUS_RDYCAP   (1 << 0)
+#define AD774X_CAP_DATA_HIGH   1
+#define AD774X_CAP_DATA_MID    2
+#define AD774X_CAP_DATA_LOW    3
+#define AD774X_VT_DATA_HIGH    4
+#define AD774X_VT_DATA_MID     5
+#define AD774X_VT_DATA_LOW     6
+#define AD774X_CAP_SETUP       7
+#define AD774X_VT_SETUP                8
+#define AD774X_EXEC_SETUP      9
+#define AD774X_CFG             10
+#define AD774X_CAPDACA         11
+#define AD774X_CAPDACB         12
+#define AD774X_CAPDAC_EN       (1 << 7)
+#define AD774X_CAP_OFFH                13
+#define AD774X_CAP_OFFL                14
+#define AD774X_CAP_GAINH       15
+#define AD774X_CAP_GAINL       16
+#define AD774X_VOLT_GAINH      17
+#define AD774X_VOLT_GAINL      18
+
+#define AD774X_MAX_CONV_MODE   6
+
+/*
+ * struct ad774x_chip_info - chip specifc information
+ */
+
+struct ad774x_chip_info {
+       const char *name;
+       struct i2c_client *client;
+       struct iio_dev *indio_dev;
+       struct work_struct thresh_work;
+       bool inter;
+       s64 last_timestamp;
+       u16 cap_offs;                   /* Capacitive offset */
+       u16 cap_gain;                   /* Capacitive gain calibration */
+       u16 volt_gain;                  /* Voltage gain calibration */
+       u8  cap_setup;
+       u8  vt_setup;
+       u8  exec_setup;
+
+       char *conversion_mode;
+};
+
+struct ad774x_conversion_mode {
+       char *name;
+       u8 reg_cfg;
+};
+
+struct ad774x_conversion_mode ad774x_conv_mode_table[AD774X_MAX_CONV_MODE] = {
+       { "idle", 0 },
+       { "continuous-conversion", 1 },
+       { "single-conversion", 2 },
+       { "power-down", 3 },
+       { "offset-calibration", 5 },
+       { "gain-calibration", 6 },
+};
+
+/*
+ * ad774x register access by I2C
+ */
+
+static int ad774x_i2c_read(struct ad774x_chip_info *chip, u8 reg, u8 *data, int len)
+{
+       struct i2c_client *client = chip->client;
+       int ret;
+
+       ret = i2c_master_send(client, &reg, 1);
+       if (ret < 0) {
+               dev_err(&client->dev, "I2C write error\n");
+               return ret;
+       }
+
+       ret = i2c_master_recv(client, data, len);
+       if (ret < 0) {
+               dev_err(&client->dev, "I2C read error\n");
+               return ret;
+       }
+
+       return ret;
+}
+
+static int ad774x_i2c_write(struct ad774x_chip_info *chip, u8 reg, u8 data)
+{
+       struct i2c_client *client = chip->client;
+       int ret;
+
+       u8 tx[2] = {
+               reg,
+               data,
+       };
+
+       ret = i2c_master_send(client, tx, 2);
+       if (ret < 0)
+               dev_err(&client->dev, "I2C write error\n");
+
+       return ret;
+}
+
+/*
+ * sysfs nodes
+ */
+
+#define IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(_show)                             \
+       IIO_DEVICE_ATTR(available_conversion_modes, S_IRUGO, _show, NULL, 0)
+#define IIO_DEV_ATTR_CONVERSION_MODE(_mode, _show, _store)              \
+       IIO_DEVICE_ATTR(conversion_mode, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CAP_SETUP(_mode, _show, _store)           \
+       IIO_DEVICE_ATTR(cap_setup, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_VT_SETUP(_mode, _show, _store)              \
+       IIO_DEVICE_ATTR(in0_setup, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_EXEC_SETUP(_mode, _show, _store)              \
+       IIO_DEVICE_ATTR(exec_setup, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_VOLT_GAIN(_mode, _show, _store)           \
+       IIO_DEVICE_ATTR(in0_gain, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CAP_OFFS(_mode, _show, _store)            \
+       IIO_DEVICE_ATTR(cap_offs, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CAP_GAIN(_mode, _show, _store)            \
+       IIO_DEVICE_ATTR(cap_gain, _mode, _show, _store, 0)
+#define IIO_DEV_ATTR_CAP_DATA(_show)           \
+       IIO_DEVICE_ATTR(cap0_raw, S_IRUGO, _show, NULL, 0)
+#define IIO_DEV_ATTR_VT_DATA(_show)            \
+       IIO_DEVICE_ATTR(in0_raw, S_IRUGO, _show, NULL, 0)
+
+static ssize_t ad774x_show_conversion_modes(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int i;
+       int len = 0;
+
+       for (i = 0; i < AD774X_MAX_CONV_MODE; i++)
+               len += sprintf(buf + len, "%s ", ad774x_conv_mode_table[i].name);
+
+       len += sprintf(buf + len, "\n");
+
+       return len;
+}
+
+static IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(ad774x_show_conversion_modes);
+
+static ssize_t ad774x_show_conversion_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%s\n", chip->conversion_mode);
+}
+
+static ssize_t ad774x_store_conversion_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+       u8 cfg;
+       int i;
+
+       ad774x_i2c_read(chip, AD774X_CFG, &cfg, 1);
+
+       for (i = 0; i < AD774X_MAX_CONV_MODE; i++) {
+               if (strncmp(buf, ad774x_conv_mode_table[i].name,
+                               strlen(ad774x_conv_mode_table[i].name) - 1) == 0) {
+                       chip->conversion_mode = ad774x_conv_mode_table[i].name;
+                       cfg |= 0x18 | ad774x_conv_mode_table[i].reg_cfg;
+                       ad774x_i2c_write(chip, AD774X_CFG, cfg);
+                       return len;
+               }
+       }
+
+       dev_err(dev, "not supported conversion mode\n");
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CONVERSION_MODE(S_IRUGO | S_IWUSR,
+               ad774x_show_conversion_mode,
+               ad774x_store_conversion_mode);
+
+static ssize_t ad774x_show_dac_value(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       u8 data;
+
+       ad774x_i2c_read(chip, this_attr->address, &data, 1);
+
+       return sprintf(buf, "%02x\n", data & 0x7F);
+}
+
+static ssize_t ad774x_store_dac_value(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if (!ret) {
+               ad774x_i2c_write(chip, this_attr->address,
+                       (data ? AD774X_CAPDAC_EN : 0) | (data & 0x7F));
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEVICE_ATTR(capdac0_raw, S_IRUGO | S_IWUSR,
+                       ad774x_show_dac_value,
+                       ad774x_store_dac_value,
+                       AD774X_CAPDACA);
+
+static IIO_DEVICE_ATTR(capdac1_raw, S_IRUGO | S_IWUSR,
+                       ad774x_show_dac_value,
+                       ad774x_store_dac_value,
+                       AD774X_CAPDACB);
+
+static ssize_t ad774x_show_cap_setup(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "0x%02x\n", chip->cap_setup);
+}
+
+static ssize_t ad774x_store_cap_setup(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x100)) {
+               ad774x_i2c_write(chip, AD774X_CAP_SETUP, data);
+               chip->cap_setup = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CAP_SETUP(S_IRUGO | S_IWUSR,
+               ad774x_show_cap_setup,
+               ad774x_store_cap_setup);
+
+static ssize_t ad774x_show_vt_setup(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "0x%02x\n", chip->vt_setup);
+}
+
+static ssize_t ad774x_store_vt_setup(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x100)) {
+               ad774x_i2c_write(chip, AD774X_VT_SETUP, data);
+               chip->vt_setup = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_VT_SETUP(S_IRUGO | S_IWUSR,
+               ad774x_show_vt_setup,
+               ad774x_store_vt_setup);
+
+static ssize_t ad774x_show_exec_setup(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "0x%02x\n", chip->exec_setup);
+}
+
+static ssize_t ad774x_store_exec_setup(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x100)) {
+               ad774x_i2c_write(chip, AD774X_EXEC_SETUP, data);
+               chip->exec_setup = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_EXEC_SETUP(S_IRUGO | S_IWUSR,
+               ad774x_show_exec_setup,
+               ad774x_store_exec_setup);
+
+static ssize_t ad774x_show_volt_gain(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", chip->volt_gain);
+}
+
+static ssize_t ad774x_store_volt_gain(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x10000)) {
+               ad774x_i2c_write(chip, AD774X_VOLT_GAINH, data >> 8);
+               ad774x_i2c_write(chip, AD774X_VOLT_GAINL, data);
+               chip->volt_gain = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_VOLT_GAIN(S_IRUGO | S_IWUSR,
+               ad774x_show_volt_gain,
+               ad774x_store_volt_gain);
+
+static ssize_t ad774x_show_cap_data(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       char tmp[3];
+
+       ad774x_i2c_read(chip, AD774X_CAP_DATA_HIGH, tmp, 3);
+       data = ((int)tmp[0] << 16) | ((int)tmp[1] << 8) | (int)tmp[2];
+
+       return sprintf(buf, "%ld\n", data);
+}
+
+static IIO_DEV_ATTR_CAP_DATA(ad774x_show_cap_data);
+
+static ssize_t ad774x_show_vt_data(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       char tmp[3];
+
+       ad774x_i2c_read(chip, AD774X_VT_DATA_HIGH, tmp, 3);
+       data = ((int)tmp[0] << 16) | ((int)tmp[1] << 8) | (int)tmp[2];
+
+       return sprintf(buf, "%ld\n", data);
+}
+
+static IIO_DEV_ATTR_VT_DATA(ad774x_show_vt_data);
+
+static ssize_t ad774x_show_cap_offs(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", chip->cap_offs);
+}
+
+static ssize_t ad774x_store_cap_offs(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x10000)) {
+               ad774x_i2c_write(chip, AD774X_CAP_OFFH, data >> 8);
+               ad774x_i2c_write(chip, AD774X_CAP_OFFL, data);
+               chip->cap_offs = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CAP_OFFS(S_IRUGO | S_IWUSR,
+               ad774x_show_cap_offs,
+               ad774x_store_cap_offs);
+
+static ssize_t ad774x_show_cap_gain(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", chip->cap_gain);
+}
+
+static ssize_t ad774x_store_cap_gain(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+
+       if ((!ret) && (data < 0x10000)) {
+               ad774x_i2c_write(chip, AD774X_CAP_GAINH, data >> 8);
+               ad774x_i2c_write(chip, AD774X_CAP_GAINL, data);
+               chip->cap_gain = data;
+               return len;
+       }
+
+       return -EINVAL;
+}
+
+static IIO_DEV_ATTR_CAP_GAIN(S_IRUGO | S_IWUSR,
+               ad774x_show_cap_gain,
+               ad774x_store_cap_gain);
+
+static ssize_t ad774x_show_name(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+       return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad774x_show_name, NULL, 0);
+
+static struct attribute *ad774x_attributes[] = {
+       &iio_dev_attr_available_conversion_modes.dev_attr.attr,
+       &iio_dev_attr_conversion_mode.dev_attr.attr,
+       &iio_dev_attr_cap_setup.dev_attr.attr,
+       &iio_dev_attr_in0_setup.dev_attr.attr,
+       &iio_dev_attr_exec_setup.dev_attr.attr,
+       &iio_dev_attr_cap_offs.dev_attr.attr,
+       &iio_dev_attr_cap_gain.dev_attr.attr,
+       &iio_dev_attr_in0_gain.dev_attr.attr,
+       &iio_dev_attr_in0_raw.dev_attr.attr,
+       &iio_dev_attr_cap0_raw.dev_attr.attr,
+       &iio_dev_attr_capdac0_raw.dev_attr.attr,
+       &iio_dev_attr_capdac1_raw.dev_attr.attr,
+       &iio_dev_attr_name.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ad774x_attribute_group = {
+       .attrs = ad774x_attributes,
+};
+
+/*
+ * data ready events
+ */
+
+#define IIO_EVENT_CODE_CAP_RDY     IIO_BUFFER_EVENT_CODE(0)
+#define IIO_EVENT_CODE_VT_RDY      IIO_BUFFER_EVENT_CODE(1)
+
+#define IIO_EVENT_ATTR_CAP_RDY_SH(_evlist, _show, _store, _mask)       \
+       IIO_EVENT_ATTR_SH(cap_rdy, _evlist, _show, _store, _mask)
+
+#define IIO_EVENT_ATTR_VT_RDY_SH(_evlist, _show, _store, _mask)        \
+       IIO_EVENT_ATTR_SH(vt_rdy, _evlist, _show, _store, _mask)
+
+static void ad774x_interrupt_handler_bh(struct work_struct *work_s)
+{
+       struct ad774x_chip_info *chip =
+               container_of(work_s, struct ad774x_chip_info, thresh_work);
+       u8 int_status;
+
+       enable_irq(chip->client->irq);
+
+       ad774x_i2c_read(chip, AD774X_STATUS, &int_status, 1);
+
+       if (int_status & AD774X_STATUS_RDYCAP)
+               iio_push_event(chip->indio_dev, 0,
+                               IIO_EVENT_CODE_CAP_RDY,
+                               chip->last_timestamp);
+
+       if (int_status & AD774X_STATUS_RDYVT)
+               iio_push_event(chip->indio_dev, 0,
+                               IIO_EVENT_CODE_VT_RDY,
+                               chip->last_timestamp);
+}
+
+static int ad774x_interrupt_handler_th(struct iio_dev *dev_info,
+               int index,
+               s64 timestamp,
+               int no_test)
+{
+       struct ad774x_chip_info *chip = dev_info->dev_data;
+
+       chip->last_timestamp = timestamp;
+       schedule_work(&chip->thresh_work);
+
+       return 0;
+}
+
+IIO_EVENT_SH(data_rdy, &ad774x_interrupt_handler_th);
+
+static ssize_t ad774x_query_out_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       /*
+        * AD774X provides one /RDY pin, which can be used as interrupt
+        * but the pin is not configurable
+        */
+       return sprintf(buf, "1\n");
+}
+
+static ssize_t ad774x_set_out_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return len;
+}
+
+IIO_EVENT_ATTR_CAP_RDY_SH(iio_event_data_rdy, ad774x_query_out_mode, ad774x_set_out_mode, 0);
+IIO_EVENT_ATTR_VT_RDY_SH(iio_event_data_rdy, ad774x_query_out_mode, ad774x_set_out_mode, 0);
+
+static struct attribute *ad774x_event_attributes[] = {
+       &iio_event_attr_cap_rdy.dev_attr.attr,
+       &iio_event_attr_vt_rdy.dev_attr.attr,
+       NULL,
+};
+
+static struct attribute_group ad774x_event_attribute_group = {
+       .attrs = ad774x_event_attributes,
+};
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit ad774x_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       int ret = 0, regdone = 0;
+       struct ad774x_chip_info *chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (chip == NULL) {
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+
+       /* this is only used for device removal purposes */
+       i2c_set_clientdata(client, chip);
+
+       chip->client = client;
+       chip->name = id->name;
+
+       chip->indio_dev = iio_allocate_device();
+       if (chip->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_chip;
+       }
+
+       /* Establish that the iio_dev is a child of the i2c device */
+       chip->indio_dev->dev.parent = &client->dev;
+       chip->indio_dev->attrs = &ad774x_attribute_group;
+       chip->indio_dev->event_attrs = &ad774x_event_attribute_group;
+       chip->indio_dev->dev_data = (void *)(chip);
+       chip->indio_dev->driver_module = THIS_MODULE;
+       chip->indio_dev->num_interrupt_lines = 1;
+       chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(chip->indio_dev);
+       if (ret)
+               goto error_free_dev;
+       regdone = 1;
+
+       if (client->irq) {
+               ret = iio_register_interrupt_line(client->irq,
+                               chip->indio_dev,
+                               0,
+                               IRQF_TRIGGER_FALLING,
+                               "ad774x");
+               if (ret)
+                       goto error_free_dev;
+
+               iio_add_event_to_list(iio_event_attr_cap_rdy.listel,
+                               &chip->indio_dev->interrupts[0]->ev_list);
+
+               INIT_WORK(&chip->thresh_work, ad774x_interrupt_handler_bh);
+       }
+
+       dev_err(&client->dev, "%s capacitive sensor registered, irq: %d\n", id->name, client->irq);
+
+       return 0;
+
+error_free_dev:
+       if (regdone)
+               iio_device_unregister(chip->indio_dev);
+       else
+               iio_free_device(chip->indio_dev);
+error_free_chip:
+       kfree(chip);
+error_ret:
+       return ret;
+}
+
+static int __devexit ad774x_remove(struct i2c_client *client)
+{
+       struct ad774x_chip_info *chip = i2c_get_clientdata(client);
+       struct iio_dev *indio_dev = chip->indio_dev;
+
+       if (client->irq)
+               iio_unregister_interrupt_line(indio_dev, 0);
+       iio_device_unregister(indio_dev);
+       kfree(chip);
+
+       return 0;
+}
+
+static const struct i2c_device_id ad774x_id[] = {
+       { "ad7745", 0 },
+       { "ad7746", 0 },
+       { "ad7747", 0 },
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, ad774x_id);
+
+static struct i2c_driver ad774x_driver = {
+       .driver = {
+               .name = "ad774x",
+       },
+       .probe = ad774x_probe,
+       .remove = __devexit_p(ad774x_remove),
+       .id_table = ad774x_id,
+};
+
+static __init int ad774x_init(void)
+{
+       return i2c_add_driver(&ad774x_driver);
+}
+
+static __exit void ad774x_exit(void)
+{
+       i2c_del_driver(&ad774x_driver);
+}
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ad7745/6/7 capacitive sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(ad774x_init);
+module_exit(ad774x_exit);
diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c
new file mode 100644 (file)
index 0000000..ad7415a
--- /dev/null
@@ -0,0 +1,535 @@
+/*
+ * AD7816 digital temperature sensor driver supporting AD7816/7/8
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * AD7816 config masks
+ */
+#define AD7816_FULL                    0x1
+#define AD7816_PD                      0x2
+#define AD7816_CS_MASK                 0x7
+#define AD7816_CS_MAX                  0x4
+
+/*
+ * AD7816 temperature masks
+ */
+#define AD7816_VALUE_OFFSET            6
+#define AD7816_BOUND_VALUE_BASE                0x8
+#define AD7816_BOUND_VALUE_MIN         -95
+#define AD7816_BOUND_VALUE_MAX         152
+#define AD7816_TEMP_FLOAT_OFFSET       2
+#define AD7816_TEMP_FLOAT_MASK         0x3
+
+
+/*
+ * struct ad7816_chip_info - chip specifc information
+ */
+
+struct ad7816_chip_info {
+       const char *name;
+       struct spi_device *spi_dev;
+       struct iio_dev *indio_dev;
+       struct work_struct thresh_work;
+       s64 last_timestamp;
+       u16 rdwr_pin;
+       u16 convert_pin;
+       u16 busy_pin;
+       u8  oti_data[AD7816_CS_MAX+1];
+       u8  channel_id; /* 0 always be temperature */
+       u8  mode;
+};
+
+/*
+ * ad7816 data access by SPI
+ */
+static int ad7816_spi_read(struct ad7816_chip_info *chip, u16 *data)
+{
+       struct spi_device *spi_dev = chip->spi_dev;
+       int ret = 0;
+
+       gpio_set_value(chip->rdwr_pin, 1);
+       gpio_set_value(chip->rdwr_pin, 0);
+       ret = spi_write(spi_dev, &chip->channel_id, sizeof(chip->channel_id));
+       if (ret < 0) {
+               dev_err(&spi_dev->dev, "SPI channel setting error\n");
+               return ret;
+       }
+       gpio_set_value(chip->rdwr_pin, 1);
+
+
+       if (chip->mode == AD7816_PD) { /* operating mode 2 */
+               gpio_set_value(chip->convert_pin, 1);
+               gpio_set_value(chip->convert_pin, 0);
+       } else { /* operating mode 1 */
+               gpio_set_value(chip->convert_pin, 0);
+               gpio_set_value(chip->convert_pin, 1);
+       }
+
+       while (gpio_get_value(chip->busy_pin))
+               cpu_relax();
+
+       gpio_set_value(chip->rdwr_pin, 0);
+       gpio_set_value(chip->rdwr_pin, 1);
+       ret = spi_read(spi_dev, (u8 *)data, sizeof(*data));
+       if (ret < 0) {
+               dev_err(&spi_dev->dev, "SPI data read error\n");
+               return ret;
+       }
+
+       *data = be16_to_cpu(*data);
+
+       return ret;
+}
+
+static int ad7816_spi_write(struct ad7816_chip_info *chip, u8 data)
+{
+       struct spi_device *spi_dev = chip->spi_dev;
+       int ret = 0;
+
+       gpio_set_value(chip->rdwr_pin, 1);
+       gpio_set_value(chip->rdwr_pin, 0);
+       ret = spi_write(spi_dev, &data, sizeof(data));
+       if (ret < 0)
+               dev_err(&spi_dev->dev, "SPI oti data write error\n");
+
+       return ret;
+}
+
+static ssize_t ad7816_show_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7816_chip_info *chip = dev_info->dev_data;
+
+       if (chip->mode)
+               return sprintf(buf, "power-save\n");
+       else
+               return sprintf(buf, "full\n");
+}
+
+static ssize_t ad7816_store_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7816_chip_info *chip = dev_info->dev_data;
+
+       if (strcmp(buf, "full")) {
+               gpio_set_value(chip->rdwr_pin, 1);
+               chip->mode = AD7816_FULL;
+       } else {
+               gpio_set_value(chip->rdwr_pin, 0);
+               chip->mode = AD7816_PD;
+       }
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+               ad7816_show_mode,
+               ad7816_store_mode,
+               0);
+
+static ssize_t ad7816_show_available_modes(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return sprintf(buf, "full\npower-save\n");
+}
+
+static IIO_DEVICE_ATTR(available_modes, S_IRUGO, ad7816_show_available_modes, NULL, 0);
+
+static ssize_t ad7816_show_channel(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7816_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", chip->channel_id);
+}
+
+static ssize_t ad7816_store_channel(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7816_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+       if (ret)
+               return -EINVAL;
+
+       if (data > AD7816_CS_MAX && data != AD7816_CS_MASK) {
+               dev_err(&chip->spi_dev->dev, "Invalid channel id %lu for %s.\n",
+                       data, chip->name);
+               return -EINVAL;
+       } else if (strcmp(chip->name, "ad7818") == 0 && data > 1) {
+               dev_err(&chip->spi_dev->dev,
+                       "Invalid channel id %lu for ad7818.\n", data);
+               return -EINVAL;
+       } else if (strcmp(chip->name, "ad7816") == 0 && data > 0) {
+               dev_err(&chip->spi_dev->dev,
+                       "Invalid channel id %lu for ad7816.\n", data);
+               return -EINVAL;
+       }
+
+       chip->channel_id = data;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(channel, S_IRUGO | S_IWUSR,
+               ad7816_show_channel,
+               ad7816_store_channel,
+               0);
+
+
+static ssize_t ad7816_show_value(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7816_chip_info *chip = dev_info->dev_data;
+       u16 data;
+       s8 value;
+       int ret;
+
+       ret = ad7816_spi_read(chip, &data);
+       if (ret)
+               return -EIO;
+
+       data >>= AD7816_VALUE_OFFSET;
+
+       if (chip->channel_id == 0) {
+               value = (s8)((data >> AD7816_TEMP_FLOAT_OFFSET) - 103);
+               data &= AD7816_TEMP_FLOAT_MASK;
+               if (value < 0)
+                       data = (1 << AD7816_TEMP_FLOAT_OFFSET) - data;
+               return sprintf(buf, "%d.%.2d\n", value, data * 25);
+       } else
+               return sprintf(buf, "%u\n", data);
+}
+
+static IIO_DEVICE_ATTR(value, S_IRUGO, ad7816_show_value, NULL, 0);
+
+static ssize_t ad7816_show_name(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7816_chip_info *chip = dev_info->dev_data;
+       return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, ad7816_show_name, NULL, 0);
+
+static struct attribute *ad7816_attributes[] = {
+       &iio_dev_attr_available_modes.dev_attr.attr,
+       &iio_dev_attr_mode.dev_attr.attr,
+       &iio_dev_attr_channel.dev_attr.attr,
+       &iio_dev_attr_value.dev_attr.attr,
+       &iio_dev_attr_name.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ad7816_attribute_group = {
+       .attrs = ad7816_attributes,
+};
+
+/*
+ * temperature bound events
+ */
+
+#define IIO_EVENT_CODE_AD7816_OTI    IIO_BUFFER_EVENT_CODE(0)
+
+static void ad7816_interrupt_bh(struct work_struct *work_s)
+{
+       struct ad7816_chip_info *chip =
+               container_of(work_s, struct ad7816_chip_info, thresh_work);
+
+       enable_irq(chip->spi_dev->irq);
+
+       iio_push_event(chip->indio_dev, 0,
+                       IIO_EVENT_CODE_AD7816_OTI,
+                       chip->last_timestamp);
+}
+
+static int ad7816_interrupt(struct iio_dev *dev_info,
+               int index,
+               s64 timestamp,
+               int no_test)
+{
+       struct ad7816_chip_info *chip = dev_info->dev_data;
+
+       chip->last_timestamp = timestamp;
+       schedule_work(&chip->thresh_work);
+
+       return 0;
+}
+
+IIO_EVENT_SH(ad7816, &ad7816_interrupt);
+
+static ssize_t ad7816_show_oti(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7816_chip_info *chip = dev_info->dev_data;
+       int value;
+
+       if (chip->channel_id > AD7816_CS_MAX) {
+               dev_err(dev, "Invalid oti channel id %d.\n", chip->channel_id);
+               return -EINVAL;
+       } else if (chip->channel_id == 0) {
+               value = AD7816_BOUND_VALUE_MIN +
+                       (chip->oti_data[chip->channel_id] -
+                       AD7816_BOUND_VALUE_BASE);
+               return sprintf(buf, "%d\n", value);
+       } else
+               return sprintf(buf, "%u\n", chip->oti_data[chip->channel_id]);
+}
+
+static inline ssize_t ad7816_set_oti(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct ad7816_chip_info *chip = dev_info->dev_data;
+       long value;
+       u8 data;
+       int ret;
+
+       ret = strict_strtol(buf, 10, &value);
+
+       if (chip->channel_id > AD7816_CS_MAX) {
+               dev_err(dev, "Invalid oti channel id %d.\n", chip->channel_id);
+               return -EINVAL;
+       } else if (chip->channel_id == 0) {
+               if (ret || value < AD7816_BOUND_VALUE_MIN ||
+                       value > AD7816_BOUND_VALUE_MAX)
+                       return -EINVAL;
+
+               data = (u8)(value - AD7816_BOUND_VALUE_MIN +
+                       AD7816_BOUND_VALUE_BASE);
+       } else {
+               if (ret || value < AD7816_BOUND_VALUE_BASE || value > 255)
+                       return -EINVAL;
+
+               data = (u8)value;
+       }
+
+       ret = ad7816_spi_write(chip, data);
+       if (ret)
+               return -EIO;
+
+       chip->oti_data[chip->channel_id] = data;
+
+       return len;
+}
+
+IIO_EVENT_ATTR_SH(oti, iio_event_ad7816,
+               ad7816_show_oti, ad7816_set_oti, 0);
+
+static struct attribute *ad7816_event_attributes[] = {
+       &iio_event_attr_oti.dev_attr.attr,
+       NULL,
+};
+
+static struct attribute_group ad7816_event_attribute_group = {
+       .attrs = ad7816_event_attributes,
+};
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit ad7816_probe(struct spi_device *spi_dev)
+{
+       struct ad7816_chip_info *chip;
+       unsigned short *pins = spi_dev->dev.platform_data;
+       int ret = 0;
+       int i;
+
+       if (!pins) {
+               dev_err(&spi_dev->dev, "No necessary GPIO platform data.\n");
+               return -EINVAL;
+       }
+
+       chip = kzalloc(sizeof(struct ad7816_chip_info), GFP_KERNEL);
+
+       if (chip == NULL)
+               return -ENOMEM;
+
+       /* this is only used for device removal purposes */
+       dev_set_drvdata(&spi_dev->dev, chip);
+
+       chip->spi_dev = spi_dev;
+       chip->name = spi_dev->modalias;
+       for (i = 0; i <= AD7816_CS_MAX; i++)
+               chip->oti_data[i] = 203;
+       chip->rdwr_pin = pins[0];
+       chip->convert_pin = pins[1];
+       chip->busy_pin = pins[2];
+
+       ret = gpio_request(chip->rdwr_pin, chip->name);
+       if (ret) {
+               dev_err(&spi_dev->dev, "Fail to request rdwr gpio PIN %d.\n",
+                       chip->rdwr_pin);
+               goto error_free_chip;
+       }
+       gpio_direction_input(chip->rdwr_pin);
+       ret = gpio_request(chip->convert_pin, chip->name);
+       if (ret) {
+               dev_err(&spi_dev->dev, "Fail to request convert gpio PIN %d.\n",
+                       chip->convert_pin);
+               goto error_free_gpio_rdwr;
+       }
+       gpio_direction_input(chip->convert_pin);
+       ret = gpio_request(chip->busy_pin, chip->name);
+       if (ret) {
+               dev_err(&spi_dev->dev, "Fail to request busy gpio PIN %d.\n",
+                       chip->busy_pin);
+               goto error_free_gpio_convert;
+       }
+       gpio_direction_input(chip->busy_pin);
+
+       chip->indio_dev = iio_allocate_device();
+       if (chip->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_gpio;
+       }
+
+       chip->indio_dev->dev.parent = &spi_dev->dev;
+       chip->indio_dev->attrs = &ad7816_attribute_group;
+       chip->indio_dev->event_attrs = &ad7816_event_attribute_group;
+       chip->indio_dev->dev_data = (void *)chip;
+       chip->indio_dev->driver_module = THIS_MODULE;
+       chip->indio_dev->num_interrupt_lines = 1;
+       chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(chip->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       if (spi_dev->irq) {
+               /* Only low trigger is supported in ad7816/7/8 */
+               ret = iio_register_interrupt_line(spi_dev->irq,
+                               chip->indio_dev,
+                               0,
+                               IRQF_TRIGGER_LOW,
+                               chip->name);
+               if (ret)
+                       goto error_unreg_dev;
+
+               /*
+                * The event handler list element refer to iio_event_ad7816.
+                * All event attributes bind to the same event handler.
+                * So, only register event handler once.
+                */
+               iio_add_event_to_list(&iio_event_ad7816,
+                               &chip->indio_dev->interrupts[0]->ev_list);
+
+               INIT_WORK(&chip->thresh_work, ad7816_interrupt_bh);
+       }
+
+       dev_info(&spi_dev->dev, "%s temperature sensor and ADC registered.\n",
+                        chip->name);
+
+       return 0;
+
+error_unreg_dev:
+       iio_device_unregister(chip->indio_dev);
+error_free_dev:
+       iio_free_device(chip->indio_dev);
+error_free_gpio:
+       gpio_free(chip->busy_pin);
+error_free_gpio_convert:
+       gpio_free(chip->convert_pin);
+error_free_gpio_rdwr:
+       gpio_free(chip->rdwr_pin);
+error_free_chip:
+       kfree(chip);
+
+       return ret;
+}
+
+static int __devexit ad7816_remove(struct spi_device *spi_dev)
+{
+       struct ad7816_chip_info *chip = dev_get_drvdata(&spi_dev->dev);
+       struct iio_dev *indio_dev = chip->indio_dev;
+
+       dev_set_drvdata(&spi_dev->dev, NULL);
+       if (spi_dev->irq)
+               iio_unregister_interrupt_line(indio_dev, 0);
+       iio_device_unregister(indio_dev);
+       iio_free_device(chip->indio_dev);
+       gpio_free(chip->busy_pin);
+       gpio_free(chip->convert_pin);
+       gpio_free(chip->rdwr_pin);
+       kfree(chip);
+
+       return 0;
+}
+
+static const struct spi_device_id ad7816_id[] = {
+       { "ad7816", 0 },
+       { "ad7817", 0 },
+       { "ad7818", 0 },
+       {}
+};
+
+MODULE_DEVICE_TABLE(spi, ad7816_id);
+
+static struct spi_driver ad7816_driver = {
+       .driver = {
+               .name = "ad7816",
+               .bus = &spi_bus_type,
+               .owner = THIS_MODULE,
+       },
+       .probe = ad7816_probe,
+       .remove = __devexit_p(ad7816_remove),
+       .id_table = ad7816_id,
+};
+
+static __init int ad7816_init(void)
+{
+       return spi_register_driver(&ad7816_driver);
+}
+
+static __exit void ad7816_exit(void)
+{
+       spi_unregister_driver(&ad7816_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD7816/7/8 digital"
+                       " temperature sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(ad7816_init);
+module_exit(ad7816_exit);
diff --git a/drivers/staging/iio/adc/adt7310.c b/drivers/staging/iio/adc/adt7310.c
new file mode 100644 (file)
index 0000000..771a409
--- /dev/null
@@ -0,0 +1,952 @@
+/*
+ * ADT7310 digital temperature sensor driver supporting ADT7310
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * ADT7310 registers definition
+ */
+
+#define ADT7310_STATUS                 0
+#define ADT7310_CONFIG                 1
+#define ADT7310_TEMPERATURE            2
+#define ADT7310_ID                     3
+#define ADT7310_T_CRIT                 4
+#define ADT7310_T_HYST                 5
+#define ADT7310_T_ALARM_HIGH           6
+#define ADT7310_T_ALARM_LOW            7
+
+/*
+ * ADT7310 status
+ */
+#define ADT7310_STAT_T_LOW             0x10
+#define ADT7310_STAT_T_HIGH            0x20
+#define ADT7310_STAT_T_CRIT            0x40
+#define ADT7310_STAT_NOT_RDY           0x80
+
+/*
+ * ADT7310 config
+ */
+#define ADT7310_FAULT_QUEUE_MASK       0x3
+#define ADT7310_CT_POLARITY            0x4
+#define ADT7310_INT_POLARITY           0x8
+#define ADT7310_EVENT_MODE             0x10
+#define ADT7310_MODE_MASK              0x60
+#define ADT7310_ONESHOT                        0x20
+#define ADT7310_SPS                    0x40
+#define ADT7310_PD                     0x60
+#define ADT7310_RESOLUTION             0x80
+
+/*
+ * ADT7310 masks
+ */
+#define ADT7310_T16_VALUE_SIGN                 0x8000
+#define ADT7310_T16_VALUE_FLOAT_OFFSET         7
+#define ADT7310_T16_VALUE_FLOAT_MASK           0x7F
+#define ADT7310_T13_VALUE_SIGN                 0x1000
+#define ADT7310_T13_VALUE_OFFSET               3
+#define ADT7310_T13_VALUE_FLOAT_OFFSET         4
+#define ADT7310_T13_VALUE_FLOAT_MASK           0xF
+#define ADT7310_T_HYST_MASK                    0xF
+#define ADT7310_DEVICE_ID_MASK                 0x7
+#define ADT7310_MANUFACTORY_ID_MASK            0xF8
+#define ADT7310_MANUFACTORY_ID_OFFSET          3
+
+
+#define ADT7310_CMD_REG_MASK                   0x28
+#define ADT7310_CMD_REG_OFFSET                 3
+#define ADT7310_CMD_READ                       0x40
+#define ADT7310_CMD_CON_READ                   0x4
+
+#define ADT7310_IRQS                           2
+
+/*
+ * struct adt7310_chip_info - chip specifc information
+ */
+
+struct adt7310_chip_info {
+       const char *name;
+       struct spi_device *spi_dev;
+       struct iio_dev *indio_dev;
+       struct work_struct thresh_work;
+       s64 last_timestamp;
+       u8  config;
+};
+
+/*
+ * adt7310 register access by SPI
+ */
+
+static int adt7310_spi_read_word(struct adt7310_chip_info *chip, u8 reg, u16 *data)
+{
+       struct spi_device *spi_dev = chip->spi_dev;
+       u8 command = (reg << ADT7310_CMD_REG_OFFSET) & ADT7310_CMD_REG_MASK;
+       int ret = 0;
+
+       command |= ADT7310_CMD_READ;
+       ret = spi_write(spi_dev, &command, sizeof(command));
+       if (ret < 0) {
+               dev_err(&spi_dev->dev, "SPI write command error\n");
+               return ret;
+       }
+
+       ret = spi_read(spi_dev, (u8 *)data, sizeof(*data));
+       if (ret < 0) {
+               dev_err(&spi_dev->dev, "SPI read word error\n");
+               return ret;
+       }
+
+       *data = be16_to_cpu(*data);
+
+       return 0;
+}
+
+static int adt7310_spi_write_word(struct adt7310_chip_info *chip, u8 reg, u16 data)
+{
+       struct spi_device *spi_dev = chip->spi_dev;
+       u8 buf[3];
+       int ret = 0;
+
+       buf[0] = (reg << ADT7310_CMD_REG_OFFSET) & ADT7310_CMD_REG_MASK;
+       buf[1] = (u8)(data >> 8);
+       buf[2] = (u8)(data & 0xFF);
+
+       ret = spi_write(spi_dev, buf, 3);
+       if (ret < 0) {
+               dev_err(&spi_dev->dev, "SPI write word error\n");
+               return ret;
+       }
+
+       return ret;
+}
+
+static int adt7310_spi_read_byte(struct adt7310_chip_info *chip, u8 reg, u8 *data)
+{
+       struct spi_device *spi_dev = chip->spi_dev;
+       u8 command = (reg << ADT7310_CMD_REG_OFFSET) & ADT7310_CMD_REG_MASK;
+       int ret = 0;
+
+       command |= ADT7310_CMD_READ;
+       ret = spi_write(spi_dev, &command, sizeof(command));
+       if (ret < 0) {
+               dev_err(&spi_dev->dev, "SPI write command error\n");
+               return ret;
+       }
+
+       ret = spi_read(spi_dev, data, sizeof(*data));
+       if (ret < 0) {
+               dev_err(&spi_dev->dev, "SPI read byte error\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int adt7310_spi_write_byte(struct adt7310_chip_info *chip, u8 reg, u8 data)
+{
+       struct spi_device *spi_dev = chip->spi_dev;
+       u8 buf[2];
+       int ret = 0;
+
+       buf[0] = (reg << ADT7310_CMD_REG_OFFSET) & ADT7310_CMD_REG_MASK;
+       buf[1] = data;
+
+       ret = spi_write(spi_dev, buf, 2);
+       if (ret < 0) {
+               dev_err(&spi_dev->dev, "SPI write byte error\n");
+               return ret;
+       }
+
+       return ret;
+}
+
+static ssize_t adt7310_show_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7310_chip_info *chip = dev_info->dev_data;
+       u8 config;
+
+       config = chip->config & ADT7310_MODE_MASK;
+
+       switch (config) {
+       case ADT7310_PD:
+               return sprintf(buf, "power-down\n");
+       case ADT7310_ONESHOT:
+               return sprintf(buf, "one-shot\n");
+       case ADT7310_SPS:
+               return sprintf(buf, "sps\n");
+       default:
+               return sprintf(buf, "full\n");
+       }
+}
+
+static ssize_t adt7310_store_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7310_chip_info *chip = dev_info->dev_data;
+       u16 config;
+       int ret;
+
+       ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       config = chip->config & (~ADT7310_MODE_MASK);
+       if (strcmp(buf, "power-down"))
+               config |= ADT7310_PD;
+       else if (strcmp(buf, "one-shot"))
+               config |= ADT7310_ONESHOT;
+       else if (strcmp(buf, "sps"))
+               config |= ADT7310_SPS;
+
+       ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, config);
+       if (ret)
+               return -EIO;
+
+       chip->config = config;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+               adt7310_show_mode,
+               adt7310_store_mode,
+               0);
+
+static ssize_t adt7310_show_available_modes(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return sprintf(buf, "full\none-shot\nsps\npower-down\n");
+}
+
+static IIO_DEVICE_ATTR(available_modes, S_IRUGO, adt7310_show_available_modes, NULL, 0);
+
+static ssize_t adt7310_show_resolution(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7310_chip_info *chip = dev_info->dev_data;
+       int ret;
+       int bits;
+
+       ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       if (chip->config & ADT7310_RESOLUTION)
+               bits = 16;
+       else
+               bits = 13;
+
+       return sprintf(buf, "%d bits\n", bits);
+}
+
+static ssize_t adt7310_store_resolution(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7310_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       u16 config;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+       if (ret)
+               return -EINVAL;
+
+       ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       config = chip->config & (~ADT7310_RESOLUTION);
+       if (data)
+               config |= ADT7310_RESOLUTION;
+
+       ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, config);
+       if (ret)
+               return -EIO;
+
+       chip->config = config;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(resolution, S_IRUGO | S_IWUSR,
+               adt7310_show_resolution,
+               adt7310_store_resolution,
+               0);
+
+static ssize_t adt7310_show_id(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7310_chip_info *chip = dev_info->dev_data;
+       u8 id;
+       int ret;
+
+       ret = adt7310_spi_read_byte(chip, ADT7310_ID, &id);
+       if (ret)
+               return -EIO;
+
+       return sprintf(buf, "device id: 0x%x\nmanufactory id: 0x%x\n",
+                       id & ADT7310_DEVICE_ID_MASK,
+                       (id & ADT7310_MANUFACTORY_ID_MASK) >> ADT7310_MANUFACTORY_ID_OFFSET);
+}
+
+static IIO_DEVICE_ATTR(id, S_IRUGO | S_IWUSR,
+               adt7310_show_id,
+               NULL,
+               0);
+
+static ssize_t adt7310_convert_temperature(struct adt7310_chip_info *chip,
+               u16 data, char *buf)
+{
+       char sign = ' ';
+
+       if (chip->config & ADT7310_RESOLUTION) {
+               if (data & ADT7310_T16_VALUE_SIGN) {
+                       /* convert supplement to positive value */
+                       data = (u16)((ADT7310_T16_VALUE_SIGN << 1) - (u32)data);
+                       sign = '-';
+               }
+               return sprintf(buf, "%c%d.%.7d\n", sign,
+                               (data >> ADT7310_T16_VALUE_FLOAT_OFFSET),
+                               (data & ADT7310_T16_VALUE_FLOAT_MASK) * 78125);
+       } else {
+               if (data & ADT7310_T13_VALUE_SIGN) {
+                       /* convert supplement to positive value */
+                       data >>= ADT7310_T13_VALUE_OFFSET;
+                       data = (ADT7310_T13_VALUE_SIGN << 1) - data;
+                       sign = '-';
+               }
+               return sprintf(buf, "%c%d.%.4d\n", sign,
+                               (data >> ADT7310_T13_VALUE_FLOAT_OFFSET),
+                               (data & ADT7310_T13_VALUE_FLOAT_MASK) * 625);
+       }
+}
+
+static ssize_t adt7310_show_value(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7310_chip_info *chip = dev_info->dev_data;
+       u8 status;
+       u16 data;
+       int ret, i = 0;
+
+       do {
+               ret = adt7310_spi_read_byte(chip, ADT7310_STATUS, &status);
+               if (ret)
+                       return -EIO;
+               i++;
+               if (i == 10000)
+                       return -EIO;
+       } while (status & ADT7310_STAT_NOT_RDY);
+
+       ret = adt7310_spi_read_word(chip, ADT7310_TEMPERATURE, &data);
+       if (ret)
+               return -EIO;
+
+       return adt7310_convert_temperature(chip, data, buf);
+}
+
+static IIO_DEVICE_ATTR(value, S_IRUGO, adt7310_show_value, NULL, 0);
+
+static ssize_t adt7310_show_name(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7310_chip_info *chip = dev_info->dev_data;
+       return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, adt7310_show_name, NULL, 0);
+
+static struct attribute *adt7310_attributes[] = {
+       &iio_dev_attr_available_modes.dev_attr.attr,
+       &iio_dev_attr_mode.dev_attr.attr,
+       &iio_dev_attr_resolution.dev_attr.attr,
+       &iio_dev_attr_id.dev_attr.attr,
+       &iio_dev_attr_value.dev_attr.attr,
+       &iio_dev_attr_name.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group adt7310_attribute_group = {
+       .attrs = adt7310_attributes,
+};
+
+/*
+ * temperature bound events
+ */
+
+#define IIO_EVENT_CODE_ADT7310_ABOVE_ALARM    IIO_BUFFER_EVENT_CODE(0)
+#define IIO_EVENT_CODE_ADT7310_BELLOW_ALARM   IIO_BUFFER_EVENT_CODE(1)
+#define IIO_EVENT_CODE_ADT7310_ABOVE_CRIT     IIO_BUFFER_EVENT_CODE(2)
+
+static void adt7310_interrupt_bh(struct work_struct *work_s)
+{
+       struct adt7310_chip_info *chip =
+               container_of(work_s, struct adt7310_chip_info, thresh_work);
+       u8 status;
+
+       if (adt7310_spi_read_byte(chip, ADT7310_STATUS, &status))
+               return;
+
+       if (status & ADT7310_STAT_T_HIGH)
+               iio_push_event(chip->indio_dev, 0,
+                       IIO_EVENT_CODE_ADT7310_ABOVE_ALARM,
+                       chip->last_timestamp);
+       if (status & ADT7310_STAT_T_LOW)
+               iio_push_event(chip->indio_dev, 0,
+                       IIO_EVENT_CODE_ADT7310_BELLOW_ALARM,
+                       chip->last_timestamp);
+       if (status & ADT7310_STAT_T_CRIT)
+               iio_push_event(chip->indio_dev, 0,
+                       IIO_EVENT_CODE_ADT7310_ABOVE_CRIT,
+                       chip->last_timestamp);
+}
+
+static int adt7310_interrupt(struct iio_dev *dev_info,
+               int index,
+               s64 timestamp,
+               int no_test)
+{
+       struct adt7310_chip_info *chip = dev_info->dev_data;
+
+       chip->last_timestamp = timestamp;
+       schedule_work(&chip->thresh_work);
+
+       return 0;
+}
+
+IIO_EVENT_SH(adt7310, &adt7310_interrupt);
+IIO_EVENT_SH(adt7310_ct, &adt7310_interrupt);
+
+static ssize_t adt7310_show_event_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7310_chip_info *chip = dev_info->dev_data;
+       int ret;
+
+       ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       if (chip->config & ADT7310_EVENT_MODE)
+               return sprintf(buf, "interrupt\n");
+       else
+               return sprintf(buf, "comparator\n");
+}
+
+static ssize_t adt7310_set_event_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7310_chip_info *chip = dev_info->dev_data;
+       u16 config;
+       int ret;
+
+       ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       config = chip->config &= ~ADT7310_EVENT_MODE;
+       if (strcmp(buf, "comparator") != 0)
+               config |= ADT7310_EVENT_MODE;
+
+       ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, config);
+       if (ret)
+               return -EIO;
+
+       chip->config = config;
+
+       return len;
+}
+
+static ssize_t adt7310_show_available_event_modes(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return sprintf(buf, "comparator\ninterrupt\n");
+}
+
+static ssize_t adt7310_show_fault_queue(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7310_chip_info *chip = dev_info->dev_data;
+       int ret;
+
+       ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       return sprintf(buf, "%d\n", chip->config & ADT7310_FAULT_QUEUE_MASK);
+}
+
+static ssize_t adt7310_set_fault_queue(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7310_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+       u8 config;
+
+       ret = strict_strtoul(buf, 10, &data);
+       if (ret || data > 3)
+               return -EINVAL;
+
+       ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       config = chip->config & ~ADT7310_FAULT_QUEUE_MASK;
+       config |= data;
+       ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, config);
+       if (ret)
+               return -EIO;
+
+       chip->config = config;
+
+       return len;
+}
+
+static inline ssize_t adt7310_show_t_bound(struct device *dev,
+               struct device_attribute *attr,
+               u8 bound_reg,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7310_chip_info *chip = dev_info->dev_data;
+       u16 data;
+       int ret;
+
+       ret = adt7310_spi_read_word(chip, bound_reg, &data);
+       if (ret)
+               return -EIO;
+
+       return adt7310_convert_temperature(chip, data, buf);
+}
+
+static inline ssize_t adt7310_set_t_bound(struct device *dev,
+               struct device_attribute *attr,
+               u8 bound_reg,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7310_chip_info *chip = dev_info->dev_data;
+       long tmp1, tmp2;
+       u16 data;
+       char *pos;
+       int ret;
+
+       pos = strchr(buf, '.');
+
+       ret = strict_strtol(buf, 10, &tmp1);
+
+       if (ret || tmp1 > 127 || tmp1 < -128)
+               return -EINVAL;
+
+       if (pos) {
+               len = strlen(pos);
+
+               if (chip->config & ADT7310_RESOLUTION) {
+                       if (len > ADT7310_T16_VALUE_FLOAT_OFFSET)
+                               len = ADT7310_T16_VALUE_FLOAT_OFFSET;
+                       pos[len] = 0;
+                       ret = strict_strtol(pos, 10, &tmp2);
+
+                       if (!ret)
+                               tmp2 = (tmp2 / 78125) * 78125;
+               } else {
+                       if (len > ADT7310_T13_VALUE_FLOAT_OFFSET)
+                               len = ADT7310_T13_VALUE_FLOAT_OFFSET;
+                       pos[len] = 0;
+                       ret = strict_strtol(pos, 10, &tmp2);
+
+                       if (!ret)
+                               tmp2 = (tmp2 / 625) * 625;
+               }
+       }
+
+       if (tmp1 < 0)
+               data = (u16)(-tmp1);
+       else
+               data = (u16)tmp1;
+
+       if (chip->config & ADT7310_RESOLUTION) {
+               data = (data << ADT7310_T16_VALUE_FLOAT_OFFSET) |
+                       (tmp2 & ADT7310_T16_VALUE_FLOAT_MASK);
+
+               if (tmp1 < 0)
+                       /* convert positive value to supplyment */
+                       data = (u16)((ADT7310_T16_VALUE_SIGN << 1) - (u32)data);
+       } else {
+               data = (data << ADT7310_T13_VALUE_FLOAT_OFFSET) |
+                       (tmp2 & ADT7310_T13_VALUE_FLOAT_MASK);
+
+               if (tmp1 < 0)
+                       /* convert positive value to supplyment */
+                       data = (ADT7310_T13_VALUE_SIGN << 1) - data;
+               data <<= ADT7310_T13_VALUE_OFFSET;
+       }
+
+       ret = adt7310_spi_write_word(chip, bound_reg, data);
+       if (ret)
+               return -EIO;
+
+       return len;
+}
+
+static ssize_t adt7310_show_t_alarm_high(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return adt7310_show_t_bound(dev, attr,
+                       ADT7310_T_ALARM_HIGH, buf);
+}
+
+static inline ssize_t adt7310_set_t_alarm_high(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return adt7310_set_t_bound(dev, attr,
+                       ADT7310_T_ALARM_HIGH, buf, len);
+}
+
+static ssize_t adt7310_show_t_alarm_low(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return adt7310_show_t_bound(dev, attr,
+                       ADT7310_T_ALARM_LOW, buf);
+}
+
+static inline ssize_t adt7310_set_t_alarm_low(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return adt7310_set_t_bound(dev, attr,
+                       ADT7310_T_ALARM_LOW, buf, len);
+}
+
+static ssize_t adt7310_show_t_crit(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return adt7310_show_t_bound(dev, attr,
+                       ADT7310_T_CRIT, buf);
+}
+
+static inline ssize_t adt7310_set_t_crit(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return adt7310_set_t_bound(dev, attr,
+                       ADT7310_T_CRIT, buf, len);
+}
+
+static ssize_t adt7310_show_t_hyst(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7310_chip_info *chip = dev_info->dev_data;
+       int ret;
+       u8 t_hyst;
+
+       ret = adt7310_spi_read_byte(chip, ADT7310_T_HYST, &t_hyst);
+       if (ret)
+               return -EIO;
+
+       return sprintf(buf, "%d\n", t_hyst & ADT7310_T_HYST_MASK);
+}
+
+static inline ssize_t adt7310_set_t_hyst(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7310_chip_info *chip = dev_info->dev_data;
+       int ret;
+       unsigned long data;
+       u8 t_hyst;
+
+       ret = strict_strtol(buf, 10, &data);
+
+       if (ret || data > ADT7310_T_HYST_MASK)
+               return -EINVAL;
+
+       t_hyst = (u8)data;
+
+       ret = adt7310_spi_write_byte(chip, ADT7310_T_HYST, t_hyst);
+       if (ret)
+               return -EIO;
+
+       return len;
+}
+
+IIO_EVENT_ATTR_SH(event_mode, iio_event_adt7310,
+               adt7310_show_event_mode, adt7310_set_event_mode, 0);
+IIO_EVENT_ATTR_SH(available_event_modes, iio_event_adt7310,
+               adt7310_show_available_event_modes, NULL, 0);
+IIO_EVENT_ATTR_SH(fault_queue, iio_event_adt7310,
+               adt7310_show_fault_queue, adt7310_set_fault_queue, 0);
+IIO_EVENT_ATTR_SH(t_alarm_high, iio_event_adt7310,
+               adt7310_show_t_alarm_high, adt7310_set_t_alarm_high, 0);
+IIO_EVENT_ATTR_SH(t_alarm_low, iio_event_adt7310,
+               adt7310_show_t_alarm_low, adt7310_set_t_alarm_low, 0);
+IIO_EVENT_ATTR_SH(t_crit, iio_event_adt7310_ct,
+               adt7310_show_t_crit, adt7310_set_t_crit, 0);
+IIO_EVENT_ATTR_SH(t_hyst, iio_event_adt7310,
+               adt7310_show_t_hyst, adt7310_set_t_hyst, 0);
+
+static struct attribute *adt7310_event_int_attributes[] = {
+       &iio_event_attr_event_mode.dev_attr.attr,
+       &iio_event_attr_available_event_modes.dev_attr.attr,
+       &iio_event_attr_fault_queue.dev_attr.attr,
+       &iio_event_attr_t_alarm_high.dev_attr.attr,
+       &iio_event_attr_t_alarm_low.dev_attr.attr,
+       &iio_event_attr_t_hyst.dev_attr.attr,
+       NULL,
+};
+
+static struct attribute *adt7310_event_ct_attributes[] = {
+       &iio_event_attr_event_mode.dev_attr.attr,
+       &iio_event_attr_available_event_modes.dev_attr.attr,
+       &iio_event_attr_fault_queue.dev_attr.attr,
+       &iio_event_attr_t_crit.dev_attr.attr,
+       &iio_event_attr_t_hyst.dev_attr.attr,
+       NULL,
+};
+
+static struct attribute_group adt7310_event_attribute_group[ADT7310_IRQS] = {
+       {
+               .attrs = adt7310_event_int_attributes,
+       },
+       {
+               .attrs = adt7310_event_ct_attributes,
+       }
+};
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit adt7310_probe(struct spi_device *spi_dev)
+{
+       struct adt7310_chip_info *chip;
+       int ret = 0;
+       unsigned long *adt7310_platform_data = spi_dev->dev.platform_data;
+       unsigned long irq_flags;
+
+       chip = kzalloc(sizeof(struct adt7310_chip_info), GFP_KERNEL);
+
+       if (chip == NULL)
+               return -ENOMEM;
+
+       /* this is only used for device removal purposes */
+       dev_set_drvdata(&spi_dev->dev, chip);
+
+       chip->spi_dev = spi_dev;
+       chip->name = spi_dev->modalias;
+
+       chip->indio_dev = iio_allocate_device();
+       if (chip->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_chip;
+       }
+
+       chip->indio_dev->dev.parent = &spi_dev->dev;
+       chip->indio_dev->attrs = &adt7310_attribute_group;
+       chip->indio_dev->event_attrs = adt7310_event_attribute_group;
+       chip->indio_dev->dev_data = (void *)chip;
+       chip->indio_dev->driver_module = THIS_MODULE;
+       chip->indio_dev->num_interrupt_lines = ADT7310_IRQS;
+       chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(chip->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       /* CT critcal temperature event. line 0 */
+       if (spi_dev->irq) {
+               if (adt7310_platform_data[2])
+                       irq_flags = adt7310_platform_data[2];
+               else
+                       irq_flags = IRQF_TRIGGER_LOW;
+               ret = iio_register_interrupt_line(spi_dev->irq,
+                               chip->indio_dev,
+                               0,
+                               irq_flags,
+                               chip->name);
+               if (ret)
+                       goto error_unreg_dev;
+
+               /*
+                * The event handler list element refer to iio_event_adt7310.
+                * All event attributes bind to the same event handler.
+                * One event handler can only be added to one event list.
+                */
+               iio_add_event_to_list(&iio_event_adt7310,
+                               &chip->indio_dev->interrupts[0]->ev_list);
+       }
+
+       /* INT bound temperature alarm event. line 1 */
+       if (adt7310_platform_data[0]) {
+               ret = iio_register_interrupt_line(adt7310_platform_data[0],
+                               chip->indio_dev,
+                               1,
+                               adt7310_platform_data[1],
+                               chip->name);
+               if (ret)
+                       goto error_unreg_ct_irq;
+
+               /*
+                * The event handler list element refer to iio_event_adt7310.
+                * All event attributes bind to the same event handler.
+                * One event handler can only be added to one event list.
+                */
+               iio_add_event_to_list(&iio_event_adt7310_ct,
+                               &chip->indio_dev->interrupts[1]->ev_list);
+       }
+
+       if (spi_dev->irq && adt7310_platform_data[0]) {
+               INIT_WORK(&chip->thresh_work, adt7310_interrupt_bh);
+
+               ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config);
+               if (ret) {
+                       ret = -EIO;
+                       goto error_unreg_int_irq;
+               }
+
+               /* set irq polarity low level */
+               chip->config &= ~ADT7310_CT_POLARITY;
+
+               if (adt7310_platform_data[1] & IRQF_TRIGGER_HIGH)
+                       chip->config |= ADT7310_INT_POLARITY;
+               else
+                       chip->config &= ~ADT7310_INT_POLARITY;
+
+               ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, chip->config);
+               if (ret) {
+                       ret = -EIO;
+                       goto error_unreg_int_irq;
+               }
+       }
+
+       dev_info(&spi_dev->dev, "%s temperature sensor registered.\n",
+                       chip->name);
+
+       return 0;
+
+error_unreg_int_irq:
+       iio_unregister_interrupt_line(chip->indio_dev, 1);
+error_unreg_ct_irq:
+       iio_unregister_interrupt_line(chip->indio_dev, 0);
+error_unreg_dev:
+       iio_device_unregister(chip->indio_dev);
+error_free_dev:
+       iio_free_device(chip->indio_dev);
+error_free_chip:
+       kfree(chip);
+
+       return ret;
+}
+
+static int __devexit adt7310_remove(struct spi_device *spi_dev)
+{
+       struct adt7310_chip_info *chip = dev_get_drvdata(&spi_dev->dev);
+       struct iio_dev *indio_dev = chip->indio_dev;
+       unsigned long *adt7310_platform_data = spi_dev->dev.platform_data;
+
+       dev_set_drvdata(&spi_dev->dev, NULL);
+       if (adt7310_platform_data[0])
+               iio_unregister_interrupt_line(indio_dev, 1);
+       if (spi_dev->irq)
+               iio_unregister_interrupt_line(indio_dev, 0);
+       iio_device_unregister(indio_dev);
+       iio_free_device(chip->indio_dev);
+       kfree(chip);
+
+       return 0;
+}
+
+static const struct spi_device_id adt7310_id[] = {
+       { "adt7310", 0 },
+       {}
+};
+
+MODULE_DEVICE_TABLE(spi, adt7310_id);
+
+static struct spi_driver adt7310_driver = {
+       .driver = {
+               .name = "adt7310",
+               .bus = &spi_bus_type,
+               .owner = THIS_MODULE,
+       },
+       .probe = adt7310_probe,
+       .remove = __devexit_p(adt7310_remove),
+       .id_table = adt7310_id,
+};
+
+static __init int adt7310_init(void)
+{
+       return spi_register_driver(&adt7310_driver);
+}
+
+static __exit void adt7310_exit(void)
+{
+       spi_unregister_driver(&adt7310_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADT7310 digital"
+                       " temperature sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(adt7310_init);
+module_exit(adt7310_exit);
diff --git a/drivers/staging/iio/adc/adt7410.c b/drivers/staging/iio/adc/adt7410.c
new file mode 100644 (file)
index 0000000..c345f27
--- /dev/null
@@ -0,0 +1,915 @@
+/*
+ * ADT7410 digital temperature sensor driver supporting ADT7410
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * ADT7410 registers definition
+ */
+
+#define ADT7410_TEMPERATURE            0
+#define ADT7410_STATUS                 2
+#define ADT7410_CONFIG                 3
+#define ADT7410_T_ALARM_HIGH           4
+#define ADT7410_T_ALARM_LOW            6
+#define ADT7410_T_CRIT                 8
+#define ADT7410_T_HYST                 0xA
+#define ADT7410_ID                     0xB
+#define ADT7410_RESET                  0x2F
+
+/*
+ * ADT7410 status
+ */
+#define ADT7410_STAT_T_LOW             0x10
+#define ADT7410_STAT_T_HIGH            0x20
+#define ADT7410_STAT_T_CRIT            0x40
+#define ADT7410_STAT_NOT_RDY           0x80
+
+/*
+ * ADT7410 config
+ */
+#define ADT7410_FAULT_QUEUE_MASK       0x3
+#define ADT7410_CT_POLARITY            0x4
+#define ADT7410_INT_POLARITY           0x8
+#define ADT7410_EVENT_MODE             0x10
+#define ADT7410_MODE_MASK              0x60
+#define ADT7410_ONESHOT                        0x20
+#define ADT7410_SPS                    0x40
+#define ADT7410_PD                     0x60
+#define ADT7410_RESOLUTION             0x80
+
+/*
+ * ADT7410 masks
+ */
+#define ADT7410_T16_VALUE_SIGN                 0x8000
+#define ADT7410_T16_VALUE_FLOAT_OFFSET         7
+#define ADT7410_T16_VALUE_FLOAT_MASK           0x7F
+#define ADT7410_T13_VALUE_SIGN                 0x1000
+#define ADT7410_T13_VALUE_OFFSET               3
+#define ADT7410_T13_VALUE_FLOAT_OFFSET         4
+#define ADT7410_T13_VALUE_FLOAT_MASK           0xF
+#define ADT7410_T_HYST_MASK                    0xF
+#define ADT7410_DEVICE_ID_MASK                 0xF
+#define ADT7410_MANUFACTORY_ID_MASK            0xF0
+#define ADT7410_MANUFACTORY_ID_OFFSET          4
+
+#define ADT7410_IRQS                           2
+
+/*
+ * struct adt7410_chip_info - chip specifc information
+ */
+
+struct adt7410_chip_info {
+       const char *name;
+       struct i2c_client *client;
+       struct iio_dev *indio_dev;
+       struct work_struct thresh_work;
+       s64 last_timestamp;
+       u8  config;
+};
+
+/*
+ * adt7410 register access by I2C
+ */
+
+static int adt7410_i2c_read_word(struct adt7410_chip_info *chip, u8 reg, u16 *data)
+{
+       struct i2c_client *client = chip->client;
+       int ret = 0;
+
+       ret = i2c_smbus_read_word_data(client, reg);
+       if (ret < 0) {
+               dev_err(&client->dev, "I2C read error\n");
+               return ret;
+       }
+
+       *data = swab16((u16)ret);
+
+       return 0;
+}
+
+static int adt7410_i2c_write_word(struct adt7410_chip_info *chip, u8 reg, u16 data)
+{
+       struct i2c_client *client = chip->client;
+       int ret = 0;
+
+       ret = i2c_smbus_write_word_data(client, reg, swab16(data));
+       if (ret < 0)
+               dev_err(&client->dev, "I2C write error\n");
+
+       return ret;
+}
+
+static int adt7410_i2c_read_byte(struct adt7410_chip_info *chip, u8 reg, u8 *data)
+{
+       struct i2c_client *client = chip->client;
+       int ret = 0;
+
+       ret = i2c_smbus_read_byte_data(client, reg);
+       if (ret < 0) {
+               dev_err(&client->dev, "I2C read error\n");
+               return ret;
+       }
+
+       *data = (u8)ret;
+
+       return 0;
+}
+
+static int adt7410_i2c_write_byte(struct adt7410_chip_info *chip, u8 reg, u8 data)
+{
+       struct i2c_client *client = chip->client;
+       int ret = 0;
+
+       ret = i2c_smbus_write_byte_data(client, reg, data);
+       if (ret < 0)
+               dev_err(&client->dev, "I2C write error\n");
+
+       return ret;
+}
+
+static ssize_t adt7410_show_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7410_chip_info *chip = dev_info->dev_data;
+       u8 config;
+
+       config = chip->config & ADT7410_MODE_MASK;
+
+       switch (config) {
+       case ADT7410_PD:
+               return sprintf(buf, "power-down\n");
+       case ADT7410_ONESHOT:
+               return sprintf(buf, "one-shot\n");
+       case ADT7410_SPS:
+               return sprintf(buf, "sps\n");
+       default:
+               return sprintf(buf, "full\n");
+       }
+}
+
+static ssize_t adt7410_store_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7410_chip_info *chip = dev_info->dev_data;
+       u16 config;
+       int ret;
+
+       ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       config = chip->config & (~ADT7410_MODE_MASK);
+       if (strcmp(buf, "power-down"))
+               config |= ADT7410_PD;
+       else if (strcmp(buf, "one-shot"))
+               config |= ADT7410_ONESHOT;
+       else if (strcmp(buf, "sps"))
+               config |= ADT7410_SPS;
+
+       ret = adt7410_i2c_write_byte(chip, ADT7410_CONFIG, config);
+       if (ret)
+               return -EIO;
+
+       chip->config = config;
+
+       return ret;
+}
+
+static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+               adt7410_show_mode,
+               adt7410_store_mode,
+               0);
+
+static ssize_t adt7410_show_available_modes(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return sprintf(buf, "full\none-shot\nsps\npower-down\n");
+}
+
+static IIO_DEVICE_ATTR(available_modes, S_IRUGO, adt7410_show_available_modes, NULL, 0);
+
+static ssize_t adt7410_show_resolution(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7410_chip_info *chip = dev_info->dev_data;
+       int ret;
+       int bits;
+
+       ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       if (chip->config & ADT7410_RESOLUTION)
+               bits = 16;
+       else
+               bits = 13;
+
+       return sprintf(buf, "%d bits\n", bits);
+}
+
+static ssize_t adt7410_store_resolution(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7410_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       u16 config;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &data);
+       if (ret)
+               return -EINVAL;
+
+       ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       config = chip->config & (~ADT7410_RESOLUTION);
+       if (data)
+               config |= ADT7410_RESOLUTION;
+
+       ret = adt7410_i2c_write_byte(chip, ADT7410_CONFIG, config);
+       if (ret)
+               return -EIO;
+
+       chip->config = config;
+
+       return ret;
+}
+
+static IIO_DEVICE_ATTR(resolution, S_IRUGO | S_IWUSR,
+               adt7410_show_resolution,
+               adt7410_store_resolution,
+               0);
+
+static ssize_t adt7410_show_id(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7410_chip_info *chip = dev_info->dev_data;
+       u8 id;
+       int ret;
+
+       ret = adt7410_i2c_read_byte(chip, ADT7410_ID, &id);
+       if (ret)
+               return -EIO;
+
+       return sprintf(buf, "device id: 0x%x\nmanufactory id: 0x%x\n",
+                       id & ADT7410_DEVICE_ID_MASK,
+                       (id & ADT7410_MANUFACTORY_ID_MASK) >> ADT7410_MANUFACTORY_ID_OFFSET);
+}
+
+static IIO_DEVICE_ATTR(id, S_IRUGO | S_IWUSR,
+               adt7410_show_id,
+               NULL,
+               0);
+
+static ssize_t adt7410_convert_temperature(struct adt7410_chip_info *chip,
+               u16 data, char *buf)
+{
+       char sign = ' ';
+
+       if (chip->config & ADT7410_RESOLUTION) {
+               if (data & ADT7410_T16_VALUE_SIGN) {
+                       /* convert supplement to positive value */
+                       data = (u16)((ADT7410_T16_VALUE_SIGN << 1) - (u32)data);
+                       sign = '-';
+               }
+               return sprintf(buf, "%c%d.%.7d\n", sign,
+                               (data >> ADT7410_T16_VALUE_FLOAT_OFFSET),
+                               (data & ADT7410_T16_VALUE_FLOAT_MASK) * 78125);
+       } else {
+               if (data & ADT7410_T13_VALUE_SIGN) {
+                       /* convert supplement to positive value */
+                       data >>= ADT7410_T13_VALUE_OFFSET;
+                       data = (ADT7410_T13_VALUE_SIGN << 1) - data;
+                       sign = '-';
+               }
+               return sprintf(buf, "%c%d.%.4d\n", sign,
+                               (data >> ADT7410_T13_VALUE_FLOAT_OFFSET),
+                               (data & ADT7410_T13_VALUE_FLOAT_MASK) * 625);
+       }
+}
+
+static ssize_t adt7410_show_value(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7410_chip_info *chip = dev_info->dev_data;
+       u8 status;
+       u16 data;
+       int ret, i = 0;
+
+       do {
+               ret = adt7410_i2c_read_byte(chip, ADT7410_STATUS, &status);
+               if (ret)
+                       return -EIO;
+               i++;
+               if (i == 10000)
+                       return -EIO;
+       } while (status & ADT7410_STAT_NOT_RDY);
+
+       ret = adt7410_i2c_read_word(chip, ADT7410_TEMPERATURE, &data);
+       if (ret)
+               return -EIO;
+
+       return adt7410_convert_temperature(chip, data, buf);
+}
+
+static IIO_DEVICE_ATTR(value, S_IRUGO, adt7410_show_value, NULL, 0);
+
+static ssize_t adt7410_show_name(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7410_chip_info *chip = dev_info->dev_data;
+       return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, adt7410_show_name, NULL, 0);
+
+static struct attribute *adt7410_attributes[] = {
+       &iio_dev_attr_available_modes.dev_attr.attr,
+       &iio_dev_attr_mode.dev_attr.attr,
+       &iio_dev_attr_resolution.dev_attr.attr,
+       &iio_dev_attr_id.dev_attr.attr,
+       &iio_dev_attr_value.dev_attr.attr,
+       &iio_dev_attr_name.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group adt7410_attribute_group = {
+       .attrs = adt7410_attributes,
+};
+
+/*
+ * temperature bound events
+ */
+
+#define IIO_EVENT_CODE_ADT7410_ABOVE_ALARM    IIO_BUFFER_EVENT_CODE(0)
+#define IIO_EVENT_CODE_ADT7410_BELLOW_ALARM   IIO_BUFFER_EVENT_CODE(1)
+#define IIO_EVENT_CODE_ADT7410_ABOVE_CRIT     IIO_BUFFER_EVENT_CODE(2)
+
+static void adt7410_interrupt_bh(struct work_struct *work_s)
+{
+       struct adt7410_chip_info *chip =
+               container_of(work_s, struct adt7410_chip_info, thresh_work);
+       u8 status;
+
+       if (adt7410_i2c_read_byte(chip, ADT7410_STATUS, &status))
+               return;
+
+       enable_irq(chip->client->irq);
+
+       if (status & ADT7410_STAT_T_HIGH)
+               iio_push_event(chip->indio_dev, 0,
+                       IIO_EVENT_CODE_ADT7410_ABOVE_ALARM,
+                       chip->last_timestamp);
+       if (status & ADT7410_STAT_T_LOW)
+               iio_push_event(chip->indio_dev, 0,
+                       IIO_EVENT_CODE_ADT7410_BELLOW_ALARM,
+                       chip->last_timestamp);
+       if (status & ADT7410_STAT_T_CRIT)
+               iio_push_event(chip->indio_dev, 0,
+                       IIO_EVENT_CODE_ADT7410_ABOVE_CRIT,
+                       chip->last_timestamp);
+}
+
+static int adt7410_interrupt(struct iio_dev *dev_info,
+               int index,
+               s64 timestamp,
+               int no_test)
+{
+       struct adt7410_chip_info *chip = dev_info->dev_data;
+
+       chip->last_timestamp = timestamp;
+       schedule_work(&chip->thresh_work);
+
+       return 0;
+}
+
+IIO_EVENT_SH(adt7410, &adt7410_interrupt);
+IIO_EVENT_SH(adt7410_ct, &adt7410_interrupt);
+
+static ssize_t adt7410_show_event_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7410_chip_info *chip = dev_info->dev_data;
+       int ret;
+
+       ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       if (chip->config & ADT7410_EVENT_MODE)
+               return sprintf(buf, "interrupt\n");
+       else
+               return sprintf(buf, "comparator\n");
+}
+
+static ssize_t adt7410_set_event_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7410_chip_info *chip = dev_info->dev_data;
+       u16 config;
+       int ret;
+
+       ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       config = chip->config &= ~ADT7410_EVENT_MODE;
+       if (strcmp(buf, "comparator") != 0)
+               config |= ADT7410_EVENT_MODE;
+
+       ret = adt7410_i2c_write_byte(chip, ADT7410_CONFIG, config);
+       if (ret)
+               return -EIO;
+
+       chip->config = config;
+
+       return ret;
+}
+
+static ssize_t adt7410_show_available_event_modes(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return sprintf(buf, "comparator\ninterrupt\n");
+}
+
+static ssize_t adt7410_show_fault_queue(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7410_chip_info *chip = dev_info->dev_data;
+       int ret;
+
+       ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       return sprintf(buf, "%d\n", chip->config & ADT7410_FAULT_QUEUE_MASK);
+}
+
+static ssize_t adt7410_set_fault_queue(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7410_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+       u8 config;
+
+       ret = strict_strtoul(buf, 10, &data);
+       if (ret || data > 3)
+               return -EINVAL;
+
+       ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       config = chip->config & ~ADT7410_FAULT_QUEUE_MASK;
+       config |= data;
+       ret = adt7410_i2c_write_byte(chip, ADT7410_CONFIG, config);
+       if (ret)
+               return -EIO;
+
+       chip->config = config;
+
+       return ret;
+}
+
+static inline ssize_t adt7410_show_t_bound(struct device *dev,
+               struct device_attribute *attr,
+               u8 bound_reg,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7410_chip_info *chip = dev_info->dev_data;
+       u16 data;
+       int ret;
+
+       ret = adt7410_i2c_read_word(chip, bound_reg, &data);
+       if (ret)
+               return -EIO;
+
+       return adt7410_convert_temperature(chip, data, buf);
+}
+
+static inline ssize_t adt7410_set_t_bound(struct device *dev,
+               struct device_attribute *attr,
+               u8 bound_reg,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7410_chip_info *chip = dev_info->dev_data;
+       long tmp1, tmp2;
+       u16 data;
+       char *pos;
+       int ret;
+
+       pos = strchr(buf, '.');
+
+       ret = strict_strtol(buf, 10, &tmp1);
+
+       if (ret || tmp1 > 127 || tmp1 < -128)
+               return -EINVAL;
+
+       if (pos) {
+               len = strlen(pos);
+
+               if (chip->config & ADT7410_RESOLUTION) {
+                       if (len > ADT7410_T16_VALUE_FLOAT_OFFSET)
+                               len = ADT7410_T16_VALUE_FLOAT_OFFSET;
+                       pos[len] = 0;
+                       ret = strict_strtol(pos, 10, &tmp2);
+
+                       if (!ret)
+                               tmp2 = (tmp2 / 78125) * 78125;
+               } else {
+                       if (len > ADT7410_T13_VALUE_FLOAT_OFFSET)
+                               len = ADT7410_T13_VALUE_FLOAT_OFFSET;
+                       pos[len] = 0;
+                       ret = strict_strtol(pos, 10, &tmp2);
+
+                       if (!ret)
+                               tmp2 = (tmp2 / 625) * 625;
+               }
+       }
+
+       if (tmp1 < 0)
+               data = (u16)(-tmp1);
+       else
+               data = (u16)tmp1;
+
+       if (chip->config & ADT7410_RESOLUTION) {
+               data = (data << ADT7410_T16_VALUE_FLOAT_OFFSET) |
+                       (tmp2 & ADT7410_T16_VALUE_FLOAT_MASK);
+
+               if (tmp1 < 0)
+                       /* convert positive value to supplyment */
+                       data = (u16)((ADT7410_T16_VALUE_SIGN << 1) - (u32)data);
+       } else {
+               data = (data << ADT7410_T13_VALUE_FLOAT_OFFSET) |
+                       (tmp2 & ADT7410_T13_VALUE_FLOAT_MASK);
+
+               if (tmp1 < 0)
+                       /* convert positive value to supplyment */
+                       data = (ADT7410_T13_VALUE_SIGN << 1) - data;
+               data <<= ADT7410_T13_VALUE_OFFSET;
+       }
+
+       ret = adt7410_i2c_write_word(chip, bound_reg, data);
+       if (ret)
+               return -EIO;
+
+       return ret;
+}
+
+static ssize_t adt7410_show_t_alarm_high(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return adt7410_show_t_bound(dev, attr,
+                       ADT7410_T_ALARM_HIGH, buf);
+}
+
+static inline ssize_t adt7410_set_t_alarm_high(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return adt7410_set_t_bound(dev, attr,
+                       ADT7410_T_ALARM_HIGH, buf, len);
+}
+
+static ssize_t adt7410_show_t_alarm_low(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return adt7410_show_t_bound(dev, attr,
+                       ADT7410_T_ALARM_LOW, buf);
+}
+
+static inline ssize_t adt7410_set_t_alarm_low(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return adt7410_set_t_bound(dev, attr,
+                       ADT7410_T_ALARM_LOW, buf, len);
+}
+
+static ssize_t adt7410_show_t_crit(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return adt7410_show_t_bound(dev, attr,
+                       ADT7410_T_CRIT, buf);
+}
+
+static inline ssize_t adt7410_set_t_crit(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return adt7410_set_t_bound(dev, attr,
+                       ADT7410_T_CRIT, buf, len);
+}
+
+static ssize_t adt7410_show_t_hyst(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7410_chip_info *chip = dev_info->dev_data;
+       int ret;
+       u8 t_hyst;
+
+       ret = adt7410_i2c_read_byte(chip, ADT7410_T_HYST, &t_hyst);
+       if (ret)
+               return -EIO;
+
+       return sprintf(buf, "%d\n", t_hyst & ADT7410_T_HYST_MASK);
+}
+
+static inline ssize_t adt7410_set_t_hyst(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7410_chip_info *chip = dev_info->dev_data;
+       int ret;
+       unsigned long data;
+       u8 t_hyst;
+
+       ret = strict_strtol(buf, 10, &data);
+
+       if (ret || data > ADT7410_T_HYST_MASK)
+               return -EINVAL;
+
+       t_hyst = (u8)data;
+
+       ret = adt7410_i2c_write_byte(chip, ADT7410_T_HYST, t_hyst);
+       if (ret)
+               return -EIO;
+
+       return ret;
+}
+
+IIO_EVENT_ATTR_SH(event_mode, iio_event_adt7410,
+               adt7410_show_event_mode, adt7410_set_event_mode, 0);
+IIO_EVENT_ATTR_SH(available_event_modes, iio_event_adt7410,
+               adt7410_show_available_event_modes, NULL, 0);
+IIO_EVENT_ATTR_SH(fault_queue, iio_event_adt7410,
+               adt7410_show_fault_queue, adt7410_set_fault_queue, 0);
+IIO_EVENT_ATTR_SH(t_alarm_high, iio_event_adt7410,
+               adt7410_show_t_alarm_high, adt7410_set_t_alarm_high, 0);
+IIO_EVENT_ATTR_SH(t_alarm_low, iio_event_adt7410,
+               adt7410_show_t_alarm_low, adt7410_set_t_alarm_low, 0);
+IIO_EVENT_ATTR_SH(t_crit, iio_event_adt7410_ct,
+               adt7410_show_t_crit, adt7410_set_t_crit, 0);
+IIO_EVENT_ATTR_SH(t_hyst, iio_event_adt7410,
+               adt7410_show_t_hyst, adt7410_set_t_hyst, 0);
+
+static struct attribute *adt7410_event_int_attributes[] = {
+       &iio_event_attr_event_mode.dev_attr.attr,
+       &iio_event_attr_available_event_modes.dev_attr.attr,
+       &iio_event_attr_fault_queue.dev_attr.attr,
+       &iio_event_attr_t_alarm_high.dev_attr.attr,
+       &iio_event_attr_t_alarm_low.dev_attr.attr,
+       &iio_event_attr_t_hyst.dev_attr.attr,
+       NULL,
+};
+
+static struct attribute *adt7410_event_ct_attributes[] = {
+       &iio_event_attr_event_mode.dev_attr.attr,
+       &iio_event_attr_available_event_modes.dev_attr.attr,
+       &iio_event_attr_fault_queue.dev_attr.attr,
+       &iio_event_attr_t_crit.dev_attr.attr,
+       &iio_event_attr_t_hyst.dev_attr.attr,
+       NULL,
+};
+
+static struct attribute_group adt7410_event_attribute_group[ADT7410_IRQS] = {
+       {
+               .attrs = adt7410_event_int_attributes,
+       },
+       {
+               .attrs = adt7410_event_ct_attributes,
+       }
+};
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit adt7410_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct adt7410_chip_info *chip;
+       int ret = 0;
+       unsigned long *adt7410_platform_data = client->dev.platform_data;
+
+       chip = kzalloc(sizeof(struct adt7410_chip_info), GFP_KERNEL);
+
+       if (chip == NULL)
+               return -ENOMEM;
+
+       /* this is only used for device removal purposes */
+       i2c_set_clientdata(client, chip);
+
+       chip->client = client;
+       chip->name = id->name;
+
+       chip->indio_dev = iio_allocate_device();
+       if (chip->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_chip;
+       }
+
+       chip->indio_dev->dev.parent = &client->dev;
+       chip->indio_dev->attrs = &adt7410_attribute_group;
+       chip->indio_dev->event_attrs = adt7410_event_attribute_group;
+       chip->indio_dev->dev_data = (void *)chip;
+       chip->indio_dev->driver_module = THIS_MODULE;
+       chip->indio_dev->num_interrupt_lines = ADT7410_IRQS;
+       chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(chip->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       /* CT critcal temperature event. line 0 */
+       if (client->irq) {
+               ret = iio_register_interrupt_line(client->irq,
+                               chip->indio_dev,
+                               0,
+                               IRQF_TRIGGER_LOW,
+                               chip->name);
+               if (ret)
+                       goto error_unreg_dev;
+
+               /*
+                * The event handler list element refer to iio_event_adt7410.
+                * All event attributes bind to the same event handler.
+                * One event handler can only be added to one event list.
+                */
+               iio_add_event_to_list(&iio_event_adt7410,
+                               &chip->indio_dev->interrupts[0]->ev_list);
+       }
+
+       /* INT bound temperature alarm event. line 1 */
+       if (adt7410_platform_data[0]) {
+               ret = iio_register_interrupt_line(adt7410_platform_data[0],
+                               chip->indio_dev,
+                               1,
+                               adt7410_platform_data[1],
+                               chip->name);
+               if (ret)
+                       goto error_unreg_ct_irq;
+
+               /*
+                * The event handler list element refer to iio_event_adt7410.
+                * All event attributes bind to the same event handler.
+                * One event handler can only be added to one event list.
+                */
+               iio_add_event_to_list(&iio_event_adt7410_ct,
+                               &chip->indio_dev->interrupts[1]->ev_list);
+       }
+
+       if (client->irq && adt7410_platform_data[0]) {
+               INIT_WORK(&chip->thresh_work, adt7410_interrupt_bh);
+
+               ret = adt7410_i2c_read_byte(chip, ADT7410_CONFIG, &chip->config);
+               if (ret) {
+                       ret = -EIO;
+                       goto error_unreg_int_irq;
+               }
+
+               /* set irq polarity low level */
+               chip->config &= ~ADT7410_CT_POLARITY;
+
+               if (adt7410_platform_data[1] & IRQF_TRIGGER_HIGH)
+                       chip->config |= ADT7410_INT_POLARITY;
+               else
+                       chip->config &= ~ADT7410_INT_POLARITY;
+
+               ret = adt7410_i2c_write_byte(chip, ADT7410_CONFIG, chip->config);
+               if (ret) {
+                       ret = -EIO;
+                       goto error_unreg_int_irq;
+               }
+       }
+
+       dev_info(&client->dev, "%s temperature sensor registered.\n",
+                        id->name);
+
+       return 0;
+
+error_unreg_int_irq:
+       iio_unregister_interrupt_line(chip->indio_dev, 1);
+error_unreg_ct_irq:
+       iio_unregister_interrupt_line(chip->indio_dev, 0);
+error_unreg_dev:
+       iio_device_unregister(chip->indio_dev);
+error_free_dev:
+       iio_free_device(chip->indio_dev);
+error_free_chip:
+       kfree(chip);
+
+       return ret;
+}
+
+static int __devexit adt7410_remove(struct i2c_client *client)
+{
+       struct adt7410_chip_info *chip = i2c_get_clientdata(client);
+       struct iio_dev *indio_dev = chip->indio_dev;
+       unsigned long *adt7410_platform_data = client->dev.platform_data;
+
+       if (adt7410_platform_data[0])
+               iio_unregister_interrupt_line(indio_dev, 1);
+       if (client->irq)
+               iio_unregister_interrupt_line(indio_dev, 0);
+       iio_device_unregister(indio_dev);
+       iio_free_device(chip->indio_dev);
+       kfree(chip);
+
+       return 0;
+}
+
+static const struct i2c_device_id adt7410_id[] = {
+       { "adt7410", 0 },
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, adt7410_id);
+
+static struct i2c_driver adt7410_driver = {
+       .driver = {
+               .name = "adt7410",
+       },
+       .probe = adt7410_probe,
+       .remove = __devexit_p(adt7410_remove),
+       .id_table = adt7410_id,
+};
+
+static __init int adt7410_init(void)
+{
+       return i2c_add_driver(&adt7410_driver);
+}
+
+static __exit void adt7410_exit(void)
+{
+       i2c_del_driver(&adt7410_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADT7410 digital"
+                       " temperature sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(adt7410_init);
+module_exit(adt7410_exit);
diff --git a/drivers/staging/iio/adc/adt75.c b/drivers/staging/iio/adc/adt75.c
new file mode 100644 (file)
index 0000000..aff4d31
--- /dev/null
@@ -0,0 +1,732 @@
+/*
+ * ADT75 digital temperature sensor driver supporting ADT75
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+/*
+ * ADT75 registers definition
+ */
+
+#define ADT75_TEMPERATURE              0
+#define ADT75_CONFIG                   1
+#define ADT75_T_HYST                   2
+#define ADT75_T_OS                     3
+#define ADT75_ONESHOT                  4
+
+/*
+ * ADT75 config
+ */
+#define ADT75_PD                       0x1
+#define ADT75_OS_INT                   0x2
+#define ADT75_OS_POLARITY              0x4
+#define ADT75_FAULT_QUEUE_MASK         0x18
+#define ADT75_FAULT_QUEUE_OFFSET       3
+#define ADT75_SMBUS_ALART              0x8
+
+/*
+ * ADT75 masks
+ */
+#define ADT75_VALUE_SIGN               0x800
+#define ADT75_VALUE_OFFSET             4
+#define ADT75_VALUE_FLOAT_OFFSET       4
+#define ADT75_VALUE_FLOAT_MASK         0xF
+
+
+/*
+ * struct adt75_chip_info - chip specifc information
+ */
+
+struct adt75_chip_info {
+       const char *name;
+       struct i2c_client *client;
+       struct iio_dev *indio_dev;
+       struct work_struct thresh_work;
+       s64 last_timestamp;
+       u8  config;
+};
+
+/*
+ * adt75 register access by I2C
+ */
+
+static int adt75_i2c_read(struct adt75_chip_info *chip, u8 reg, u8 *data)
+{
+       struct i2c_client *client = chip->client;
+       int ret = 0, len;
+
+       ret = i2c_smbus_write_byte(client, reg);
+       if (ret < 0) {
+               dev_err(&client->dev, "I2C read register address error\n");
+               return ret;
+       }
+
+       if (reg == ADT75_CONFIG || reg == ADT75_ONESHOT)
+               len = 1;
+       else
+               len = 2;
+
+       ret = i2c_master_recv(client, data, len);
+       if (ret < 0) {
+               dev_err(&client->dev, "I2C read error\n");
+               return ret;
+       }
+
+       return ret;
+}
+
+static int adt75_i2c_write(struct adt75_chip_info *chip, u8 reg, u8 data)
+{
+       struct i2c_client *client = chip->client;
+       int ret = 0;
+
+       if (reg == ADT75_CONFIG || reg == ADT75_ONESHOT)
+               ret = i2c_smbus_write_byte_data(client, reg, data);
+       else
+               ret = i2c_smbus_write_word_data(client, reg, data);
+
+       if (ret < 0)
+               dev_err(&client->dev, "I2C write error\n");
+
+       return ret;
+}
+
+static ssize_t adt75_show_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt75_chip_info *chip = dev_info->dev_data;
+
+       if (chip->config & ADT75_PD)
+               return sprintf(buf, "power-save\n");
+       else
+               return sprintf(buf, "full\n");
+}
+
+static ssize_t adt75_store_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt75_chip_info *chip = dev_info->dev_data;
+       int ret;
+       u8 config;
+
+       ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       config = chip->config & ~ADT75_PD;
+       if (!strcmp(buf, "full"))
+               config |= ADT75_PD;
+
+       ret = adt75_i2c_write(chip, ADT75_CONFIG, config);
+       if (ret)
+               return -EIO;
+
+       chip->config = config;
+
+       return ret;
+}
+
+static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+               adt75_show_mode,
+               adt75_store_mode,
+               0);
+
+static ssize_t adt75_show_available_modes(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return sprintf(buf, "full\npower-down\n");
+}
+
+static IIO_DEVICE_ATTR(available_modes, S_IRUGO, adt75_show_available_modes, NULL, 0);
+
+static ssize_t adt75_show_oneshot(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt75_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", !!(chip->config & ADT75_ONESHOT));
+}
+
+static ssize_t adt75_store_oneshot(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt75_chip_info *chip = dev_info->dev_data;
+       unsigned long data = 0;
+       int ret;
+       u8 config;
+
+       ret = strict_strtoul(buf, 10, &data);
+       if (ret)
+               return -EINVAL;
+
+
+       ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       config = chip->config & ~ADT75_ONESHOT;
+       if (data)
+               config |= ADT75_ONESHOT;
+
+       ret = adt75_i2c_write(chip, ADT75_CONFIG, config);
+       if (ret)
+               return -EIO;
+
+       chip->config = config;
+
+       return ret;
+}
+
+static IIO_DEVICE_ATTR(oneshot, S_IRUGO | S_IWUSR,
+               adt75_show_oneshot,
+               adt75_store_oneshot,
+               0);
+
+static ssize_t adt75_show_value(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt75_chip_info *chip = dev_info->dev_data;
+       u16 data;
+       char sign = ' ';
+       int ret;
+
+       if (chip->config & ADT75_PD) {
+               dev_err(dev, "Can't read value in power-down mode.\n");
+               return -EIO;
+       }
+
+       if (chip->config & ADT75_ONESHOT) {
+               /* write to active converter */
+               ret = i2c_smbus_write_byte(chip->client, ADT75_ONESHOT);
+               if (ret)
+                       return -EIO;
+       }
+
+       ret = adt75_i2c_read(chip, ADT75_TEMPERATURE, (u8 *)&data);
+       if (ret)
+               return -EIO;
+
+       data = swab16(data) >> ADT75_VALUE_OFFSET;
+       if (data & ADT75_VALUE_SIGN) {
+               /* convert supplement to positive value */
+               data = (ADT75_VALUE_SIGN << 1) - data;
+               sign = '-';
+       }
+
+       return sprintf(buf, "%c%d.%.4d\n", sign,
+               (data >> ADT75_VALUE_FLOAT_OFFSET),
+               (data & ADT75_VALUE_FLOAT_MASK) * 625);
+}
+
+static IIO_DEVICE_ATTR(value, S_IRUGO, adt75_show_value, NULL, 0);
+
+static ssize_t adt75_show_name(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt75_chip_info *chip = dev_info->dev_data;
+       return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, adt75_show_name, NULL, 0);
+
+static struct attribute *adt75_attributes[] = {
+       &iio_dev_attr_available_modes.dev_attr.attr,
+       &iio_dev_attr_mode.dev_attr.attr,
+       &iio_dev_attr_oneshot.dev_attr.attr,
+       &iio_dev_attr_value.dev_attr.attr,
+       &iio_dev_attr_name.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group adt75_attribute_group = {
+       .attrs = adt75_attributes,
+};
+
+/*
+ * temperature bound events
+ */
+
+#define IIO_EVENT_CODE_ADT75_OTI    IIO_BUFFER_EVENT_CODE(0)
+
+static void adt75_interrupt_bh(struct work_struct *work_s)
+{
+       struct adt75_chip_info *chip =
+               container_of(work_s, struct adt75_chip_info, thresh_work);
+
+       enable_irq(chip->client->irq);
+
+       iio_push_event(chip->indio_dev, 0,
+                       IIO_EVENT_CODE_ADT75_OTI,
+                       chip->last_timestamp);
+}
+
+static int adt75_interrupt(struct iio_dev *dev_info,
+               int index,
+               s64 timestamp,
+               int no_test)
+{
+       struct adt75_chip_info *chip = dev_info->dev_data;
+
+       chip->last_timestamp = timestamp;
+       schedule_work(&chip->thresh_work);
+
+       return 0;
+}
+
+IIO_EVENT_SH(adt75, &adt75_interrupt);
+
+static ssize_t adt75_show_oti_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt75_chip_info *chip = dev_info->dev_data;
+       int ret;
+
+       /* retrive ALART status */
+       ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       if (chip->config & ADT75_OS_INT)
+               return sprintf(buf, "interrupt\n");
+       else
+               return sprintf(buf, "comparator\n");
+}
+
+static ssize_t adt75_set_oti_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt75_chip_info *chip = dev_info->dev_data;
+       int ret;
+       u8 config;
+
+       /* retrive ALART status */
+       ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       config = chip->config & ~ADT75_OS_INT;
+       if (strcmp(buf, "comparator") != 0)
+               config |= ADT75_OS_INT;
+
+       ret = adt75_i2c_write(chip, ADT75_CONFIG, config);
+       if (ret)
+               return -EIO;
+
+       chip->config = config;
+
+       return ret;
+}
+
+static ssize_t adt75_show_available_oti_modes(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return sprintf(buf, "comparator\ninterrupt\n");
+}
+
+static ssize_t adt75_show_smbus_alart(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt75_chip_info *chip = dev_info->dev_data;
+       int ret;
+
+       /* retrive ALART status */
+       ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       return sprintf(buf, "%d\n", !!(chip->config & ADT75_SMBUS_ALART));
+}
+
+static ssize_t adt75_set_smbus_alart(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt75_chip_info *chip = dev_info->dev_data;
+       unsigned long data = 0;
+       int ret;
+       u8 config;
+
+       ret = strict_strtoul(buf, 10, &data);
+       if (ret)
+               return -EINVAL;
+
+       /* retrive ALART status */
+       ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       config = chip->config & ~ADT75_SMBUS_ALART;
+       if (data)
+               config |= ADT75_SMBUS_ALART;
+
+       ret = adt75_i2c_write(chip, ADT75_CONFIG, config);
+       if (ret)
+               return -EIO;
+
+       chip->config = config;
+
+       return ret;
+}
+
+static ssize_t adt75_show_fault_queue(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt75_chip_info *chip = dev_info->dev_data;
+       int ret;
+
+       /* retrive ALART status */
+       ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       return sprintf(buf, "%d\n", (chip->config & ADT75_FAULT_QUEUE_MASK) >>
+                               ADT75_FAULT_QUEUE_OFFSET);
+}
+
+static ssize_t adt75_set_fault_queue(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt75_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+       u8 config;
+
+       ret = strict_strtoul(buf, 10, &data);
+       if (ret || data > 3)
+               return -EINVAL;
+
+       /* retrive ALART status */
+       ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config);
+       if (ret)
+               return -EIO;
+
+       config = chip->config & ~ADT75_FAULT_QUEUE_MASK;
+       config |= (data << ADT75_FAULT_QUEUE_OFFSET);
+       ret = adt75_i2c_write(chip, ADT75_CONFIG, config);
+       if (ret)
+               return -EIO;
+
+       chip->config = config;
+
+       return ret;
+}
+static inline ssize_t adt75_show_t_bound(struct device *dev,
+               struct device_attribute *attr,
+               u8 bound_reg,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt75_chip_info *chip = dev_info->dev_data;
+       u16 data;
+       char sign = ' ';
+       int ret;
+
+       ret = adt75_i2c_read(chip, bound_reg, (u8 *)&data);
+       if (ret)
+               return -EIO;
+
+       data = swab16(data) >> ADT75_VALUE_OFFSET;
+       if (data & ADT75_VALUE_SIGN) {
+               /* convert supplement to positive value */
+               data = (ADT75_VALUE_SIGN << 1) - data;
+               sign = '-';
+       }
+
+       return sprintf(buf, "%c%d.%.4d\n", sign,
+               (data >> ADT75_VALUE_FLOAT_OFFSET),
+               (data & ADT75_VALUE_FLOAT_MASK) * 625);
+}
+
+static inline ssize_t adt75_set_t_bound(struct device *dev,
+               struct device_attribute *attr,
+               u8 bound_reg,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt75_chip_info *chip = dev_info->dev_data;
+       long tmp1, tmp2;
+       u16 data;
+       char *pos;
+       int ret;
+
+       pos = strchr(buf, '.');
+
+       ret = strict_strtol(buf, 10, &tmp1);
+
+       if (ret || tmp1 > 127 || tmp1 < -128)
+               return -EINVAL;
+
+       if (pos) {
+               len = strlen(pos);
+               if (len > ADT75_VALUE_FLOAT_OFFSET)
+                       len = ADT75_VALUE_FLOAT_OFFSET;
+               pos[len] = 0;
+               ret = strict_strtol(pos, 10, &tmp2);
+
+               if (!ret)
+                       tmp2 = (tmp2 / 625) * 625;
+       }
+
+       if (tmp1 < 0)
+               data = (u16)(-tmp1);
+       else
+               data = (u16)tmp1;
+       data = (data << ADT75_VALUE_FLOAT_OFFSET) | (tmp2 & ADT75_VALUE_FLOAT_MASK);
+       if (tmp1 < 0)
+               /* convert positive value to supplyment */
+               data = (ADT75_VALUE_SIGN << 1) - data;
+       data <<= ADT75_VALUE_OFFSET;
+       data = swab16(data);
+
+       ret = adt75_i2c_write(chip, bound_reg, (u8)data);
+       if (ret)
+               return -EIO;
+
+       return ret;
+}
+
+static ssize_t adt75_show_t_os(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return adt75_show_t_bound(dev, attr,
+                       ADT75_T_OS, buf);
+}
+
+static inline ssize_t adt75_set_t_os(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return adt75_set_t_bound(dev, attr,
+                       ADT75_T_OS, buf, len);
+}
+
+static ssize_t adt75_show_t_hyst(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return adt75_show_t_bound(dev, attr,
+                       ADT75_T_HYST, buf);
+}
+
+static inline ssize_t adt75_set_t_hyst(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return adt75_set_t_bound(dev, attr,
+                       ADT75_T_HYST, buf, len);
+}
+
+IIO_EVENT_ATTR_SH(oti_mode, iio_event_adt75,
+               adt75_show_oti_mode, adt75_set_oti_mode, 0);
+IIO_EVENT_ATTR_SH(available_oti_modes, iio_event_adt75,
+               adt75_show_available_oti_modes, NULL, 0);
+IIO_EVENT_ATTR_SH(smbus_alart, iio_event_adt75,
+               adt75_show_smbus_alart, adt75_set_smbus_alart, 0);
+IIO_EVENT_ATTR_SH(fault_queue, iio_event_adt75,
+               adt75_show_fault_queue, adt75_set_fault_queue, 0);
+IIO_EVENT_ATTR_SH(t_os, iio_event_adt75,
+               adt75_show_t_os, adt75_set_t_os, 0);
+IIO_EVENT_ATTR_SH(t_hyst, iio_event_adt75,
+               adt75_show_t_hyst, adt75_set_t_hyst, 0);
+
+static struct attribute *adt75_event_attributes[] = {
+       &iio_event_attr_oti_mode.dev_attr.attr,
+       &iio_event_attr_available_oti_modes.dev_attr.attr,
+       &iio_event_attr_smbus_alart.dev_attr.attr,
+       &iio_event_attr_fault_queue.dev_attr.attr,
+       &iio_event_attr_t_os.dev_attr.attr,
+       &iio_event_attr_t_hyst.dev_attr.attr,
+       NULL,
+};
+
+static struct attribute_group adt75_event_attribute_group = {
+       .attrs = adt75_event_attributes,
+};
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit adt75_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct adt75_chip_info *chip;
+       int ret = 0;
+
+       chip = kzalloc(sizeof(struct adt75_chip_info), GFP_KERNEL);
+
+       if (chip == NULL)
+               return -ENOMEM;
+
+       /* this is only used for device removal purposes */
+       i2c_set_clientdata(client, chip);
+
+       chip->client = client;
+       chip->name = id->name;
+
+       chip->indio_dev = iio_allocate_device();
+       if (chip->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_chip;
+       }
+
+       chip->indio_dev->dev.parent = &client->dev;
+       chip->indio_dev->attrs = &adt75_attribute_group;
+       chip->indio_dev->event_attrs = &adt75_event_attribute_group;
+       chip->indio_dev->dev_data = (void *)chip;
+       chip->indio_dev->driver_module = THIS_MODULE;
+       chip->indio_dev->num_interrupt_lines = 1;
+       chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(chip->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       if (client->irq > 0) {
+               ret = iio_register_interrupt_line(client->irq,
+                               chip->indio_dev,
+                               0,
+                               IRQF_TRIGGER_LOW,
+                               chip->name);
+               if (ret)
+                       goto error_unreg_dev;
+
+               /*
+                * The event handler list element refer to iio_event_adt75.
+                * All event attributes bind to the same event handler.
+                * So, only register event handler once.
+                */
+               iio_add_event_to_list(&iio_event_adt75,
+                               &chip->indio_dev->interrupts[0]->ev_list);
+
+               INIT_WORK(&chip->thresh_work, adt75_interrupt_bh);
+
+               ret = adt75_i2c_read(chip, ADT75_CONFIG, &chip->config);
+               if (ret) {
+                       ret = -EIO;
+                       goto error_unreg_irq;
+               }
+
+               /* set irq polarity low level */
+               chip->config &= ~ADT75_OS_POLARITY;
+
+               ret = adt75_i2c_write(chip, ADT75_CONFIG, chip->config);
+               if (ret) {
+                       ret = -EIO;
+                       goto error_unreg_irq;
+               }
+       }
+
+       dev_info(&client->dev, "%s temperature sensor registered.\n",
+                        id->name);
+
+       return 0;
+error_unreg_irq:
+       iio_unregister_interrupt_line(chip->indio_dev, 0);
+error_unreg_dev:
+       iio_device_unregister(chip->indio_dev);
+error_free_dev:
+       iio_free_device(chip->indio_dev);
+error_free_chip:
+       kfree(chip);
+
+       return ret;
+}
+
+static int __devexit adt75_remove(struct i2c_client *client)
+{
+       struct adt75_chip_info *chip = i2c_get_clientdata(client);
+       struct iio_dev *indio_dev = chip->indio_dev;
+
+       if (client->irq)
+               iio_unregister_interrupt_line(indio_dev, 0);
+       iio_device_unregister(indio_dev);
+       iio_free_device(chip->indio_dev);
+       kfree(chip);
+
+       return 0;
+}
+
+static const struct i2c_device_id adt75_id[] = {
+       { "adt75", 0 },
+       {}
+};
+
+MODULE_DEVICE_TABLE(i2c, adt75_id);
+
+static struct i2c_driver adt75_driver = {
+       .driver = {
+               .name = "adt75",
+       },
+       .probe = adt75_probe,
+       .remove = __devexit_p(adt75_remove),
+       .id_table = adt75_id,
+};
+
+static __init int adt75_init(void)
+{
+       return i2c_add_driver(&adt75_driver);
+}
+
+static __exit void adt75_exit(void)
+{
+       i2c_del_driver(&adt75_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADT75 digital"
+                       " temperature sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(adt75_init);
+module_exit(adt75_exit);
diff --git a/drivers/staging/iio/addac/Kconfig b/drivers/staging/iio/addac/Kconfig
new file mode 100644 (file)
index 0000000..9847baf
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# ADDAC drivers
+#
+comment "Analog digital bi-direction convertors"
+
+config ADT7316
+       tristate "Analog Devices ADT7316/7/8 ADT7516/7/9 temperature sensor, ADC and DAC driver"
+       help
+         Say yes here to build support for Analog Devices ADT7316, ADT7317, ADT7318
+         and ADT7516, ADT7517, ADT7519 temperature sensors, ADC and DAC.
+
+config ADT7316_SPI
+       tristate "support SPI bus connection"
+       depends on SPI && ADT7316
+       default y
+       help
+         Say yes here to build SPI bus support for Analog Devices ADT7316/7/8
+         and ADT7516/7/9.
+
+config ADT7316_I2C
+       tristate "support I2C bus connection"
+       depends on I2C && ADT7316
+       help
+         Say yes here to build I2C bus support for Analog Devices ADT7316/7/8
+         and ADT7516/7/9.
diff --git a/drivers/staging/iio/addac/Makefile b/drivers/staging/iio/addac/Makefile
new file mode 100644 (file)
index 0000000..4c76861
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for industrial I/O ADDAC drivers
+#
+
+obj-$(CONFIG_ADT7316) += adt7316.o
+obj-$(CONFIG_ADT7316_SPI) += adt7316-spi.o
+obj-$(CONFIG_ADT7316_I2C) += adt7316-i2c.o
diff --git a/drivers/staging/iio/addac/adt7316-i2c.c b/drivers/staging/iio/addac/adt7316-i2c.c
new file mode 100644 (file)
index 0000000..52d1ea3
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * I2C bus driver for ADT7316/7/8 ADT7516/7/9 digital temperature
+ * sensor, ADC and DAC
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+
+#include "adt7316.h"
+
+/*
+ * adt7316 register access by I2C
+ */
+static int adt7316_i2c_read(void *client, u8 reg, u8 *data)
+{
+       struct i2c_client *cl = client;
+       int ret = 0;
+
+       ret = i2c_smbus_write_byte(cl, reg);
+       if (ret < 0) {
+               dev_err(&cl->dev, "I2C fail to select reg\n");
+               return ret;
+       }
+
+       ret = i2c_smbus_read_byte(client);
+       if (ret < 0) {
+               dev_err(&cl->dev, "I2C read error\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int adt7316_i2c_write(void *client, u8 reg, u8 data)
+{
+       struct i2c_client *cl = client;
+       int ret = 0;
+
+       ret = i2c_smbus_write_byte_data(cl, reg, data);
+       if (ret < 0)
+               dev_err(&cl->dev, "I2C write error\n");
+
+       return ret;
+}
+
+static int adt7316_i2c_multi_read(void *client, u8 reg, u8 count, u8 *data)
+{
+       struct i2c_client *cl = client;
+       int i, ret = 0;
+
+       if (count > ADT7316_REG_MAX_ADDR)
+               count = ADT7316_REG_MAX_ADDR;
+
+       for (i = 0; i < count; i++) {
+               ret = adt7316_i2c_read(cl, reg, &data[i]);
+               if (ret < 0) {
+                       dev_err(&cl->dev, "I2C multi read error\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int adt7316_i2c_multi_write(void *client, u8 reg, u8 count, u8 *data)
+{
+       struct i2c_client *cl = client;
+       int i, ret = 0;
+
+       if (count > ADT7316_REG_MAX_ADDR)
+               count = ADT7316_REG_MAX_ADDR;
+
+       for (i = 0; i < count; i++) {
+               ret = adt7316_i2c_write(cl, reg, data[i]);
+               if (ret < 0) {
+                       dev_err(&cl->dev, "I2C multi write error\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit adt7316_i2c_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct adt7316_bus bus = {
+               .client = client,
+               .irq = client->irq,
+               .irq_flags = IRQF_TRIGGER_LOW,
+               .read = adt7316_i2c_read,
+               .write = adt7316_i2c_write,
+               .multi_read = adt7316_i2c_multi_read,
+               .multi_write = adt7316_i2c_multi_write,
+       };
+
+       return adt7316_probe(&client->dev, &bus, id->name);
+}
+
+static int __devexit adt7316_i2c_remove(struct i2c_client *client)
+{
+       return adt7316_remove(&client->dev);;
+}
+
+static const struct i2c_device_id adt7316_i2c_id[] = {
+       { "adt7316", 0 },
+       { "adt7317", 0 },
+       { "adt7318", 0 },
+       { "adt7516", 0 },
+       { "adt7517", 0 },
+       { "adt7519", 0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, adt7316_i2c_id);
+
+#ifdef CONFIG_PM
+static int adt7316_i2c_suspend(struct i2c_client *client, pm_message_t message)
+{
+       return adt7316_disable(&client->dev);
+}
+
+static int adt7316_i2c_resume(struct i2c_client *client)
+{
+       return adt7316_enable(&client->dev);
+}
+#else
+# define adt7316_i2c_suspend NULL
+# define adt7316_i2c_resume  NULL
+#endif
+
+static struct i2c_driver adt7316_driver = {
+       .driver = {
+               .name = "adt7316",
+               .owner  = THIS_MODULE,
+       },
+       .probe = adt7316_i2c_probe,
+       .remove = __devexit_p(adt7316_i2c_remove),
+       .suspend = adt7316_i2c_suspend,
+       .resume = adt7316_i2c_resume,
+       .id_table = adt7316_i2c_id,
+};
+
+static __init int adt7316_i2c_init(void)
+{
+       return i2c_add_driver(&adt7316_driver);
+}
+
+static __exit void adt7316_i2c_exit(void)
+{
+       i2c_del_driver(&adt7316_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("I2C bus driver for Analog Devices ADT7316/7/9 and"
+                       "ADT7516/7/8 digital temperature sensor, ADC and DAC");
+MODULE_LICENSE("GPL v2");
+
+module_init(adt7316_i2c_init);
+module_exit(adt7316_i2c_exit);
diff --git a/drivers/staging/iio/addac/adt7316-spi.c b/drivers/staging/iio/addac/adt7316-spi.c
new file mode 100644 (file)
index 0000000..369d4d0
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * API bus driver for ADT7316/7/8 ADT7516/7/9 digital temperature
+ * sensor, ADC and DAC
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/spi/spi.h>
+
+#include "adt7316.h"
+
+#define ADT7316_SPI_MAX_FREQ_HZ                5000000
+#define ADT7316_SPI_CMD_READ           0x91
+#define ADT7316_SPI_CMD_WRITE          0x90
+
+/*
+ * adt7316 register access by SPI
+ */
+
+static int adt7316_spi_multi_read(void *client, u8 reg, u8 count, u8 *data)
+{
+       struct spi_device *spi_dev = client;
+       u8 cmd[2];
+       int ret = 0;
+
+       if (count > ADT7316_REG_MAX_ADDR)
+               count = ADT7316_REG_MAX_ADDR;
+
+       cmd[0] = ADT7316_SPI_CMD_WRITE;
+       cmd[1] = reg;
+
+       ret = spi_write(spi_dev, cmd, 2);
+       if (ret < 0) {
+               dev_err(&spi_dev->dev, "SPI fail to select reg\n");
+               return ret;
+       }
+
+       cmd[0] = ADT7316_SPI_CMD_READ;
+
+       ret = spi_write_then_read(spi_dev, cmd, 1, data, count);
+       if (ret < 0) {
+               dev_err(&spi_dev->dev, "SPI read data error\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int adt7316_spi_multi_write(void *client, u8 reg, u8 count, u8 *data)
+{
+       struct spi_device *spi_dev = client;
+       u8 buf[ADT7316_REG_MAX_ADDR + 2];
+       int i, ret = 0;
+
+       if (count > ADT7316_REG_MAX_ADDR)
+               count = ADT7316_REG_MAX_ADDR;
+
+       buf[0] = ADT7316_SPI_CMD_WRITE;
+       buf[1] = reg;
+       for (i = 0; i < count; i++)
+               buf[i + 2] = data[i];
+
+       ret = spi_write(spi_dev, buf, count + 2);
+       if (ret < 0) {
+               dev_err(&spi_dev->dev, "SPI write error\n");
+               return ret;
+       }
+
+       return ret;
+}
+
+static int adt7316_spi_read(void *client, u8 reg, u8 *data)
+{
+       return adt7316_spi_multi_read(client, reg, 1, data);
+}
+
+static int adt7316_spi_write(void *client, u8 reg, u8 val)
+{
+       return adt7316_spi_multi_write(client, reg, 1, &val);
+}
+
+/*
+ * device probe and remove
+ */
+
+static int __devinit adt7316_spi_probe(struct spi_device *spi_dev)
+{
+       struct adt7316_bus bus = {
+               .client = spi_dev,
+               .irq = spi_dev->irq,
+               .irq_flags = IRQF_TRIGGER_LOW,
+               .read = adt7316_spi_read,
+               .write = adt7316_spi_write,
+               .multi_read = adt7316_spi_multi_read,
+               .multi_write = adt7316_spi_multi_write,
+       };
+
+       /* don't exceed max specified SPI CLK frequency */
+       if (spi_dev->max_speed_hz > ADT7316_SPI_MAX_FREQ_HZ) {
+               dev_err(&spi_dev->dev, "SPI CLK %d Hz?\n",
+                       spi_dev->max_speed_hz);
+               return -EINVAL;
+       }
+
+       /* switch from default I2C protocol to SPI protocol */
+       adt7316_spi_write(spi_dev, 0, 0);
+       adt7316_spi_write(spi_dev, 0, 0);
+       adt7316_spi_write(spi_dev, 0, 0);
+
+       return adt7316_probe(&spi_dev->dev, &bus, spi_dev->modalias);
+}
+
+static int __devexit adt7316_spi_remove(struct spi_device *spi_dev)
+{
+       return adt7316_remove(&spi_dev->dev);
+}
+
+static const struct spi_device_id adt7316_spi_id[] = {
+       { "adt7316", 0 },
+       { "adt7317", 0 },
+       { "adt7318", 0 },
+       { "adt7516", 0 },
+       { "adt7517", 0 },
+       { "adt7519", 0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(spi, adt7316_spi_id);
+
+#ifdef CONFIG_PM
+static int adt7316_spi_suspend(struct spi_device *spi_dev, pm_message_t message)
+{
+       return adt7316_disable(&spi_dev->dev);
+}
+
+static int adt7316_spi_resume(struct spi_device *spi_dev)
+{
+       return adt7316_enable(&spi_dev->dev);
+}
+#else
+# define adt7316_spi_suspend NULL
+# define adt7316_spi_resume  NULL
+#endif
+
+static struct spi_driver adt7316_driver = {
+       .driver = {
+               .name = "adt7316",
+               .bus = &spi_bus_type,
+               .owner = THIS_MODULE,
+       },
+       .probe = adt7316_spi_probe,
+       .remove = __devexit_p(adt7316_spi_remove),
+       .suspend = adt7316_spi_suspend,
+       .resume = adt7316_spi_resume,
+       .id_table = adt7316_spi_id,
+};
+
+static __init int adt7316_spi_init(void)
+{
+       return spi_register_driver(&adt7316_driver);
+}
+
+static __exit void adt7316_spi_exit(void)
+{
+       spi_unregister_driver(&adt7316_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("SPI bus driver for Analog Devices ADT7316/7/8 and"
+                       "ADT7516/7/9 digital temperature sensor, ADC and DAC");
+MODULE_LICENSE("GPL v2");
+
+module_init(adt7316_spi_init);
+module_exit(adt7316_spi_exit);
diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c
new file mode 100644 (file)
index 0000000..d1b5b13
--- /dev/null
@@ -0,0 +1,2402 @@
+/*
+ * ADT7316 digital temperature sensor driver supporting ADT7316/7/8 ADT7516/7/9
+ *
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "adt7316.h"
+
+/*
+ * ADT7316 registers definition
+ */
+#define ADT7316_INT_STAT1              0x0
+#define ADT7316_INT_STAT2              0x1
+#define ADT7316_LSB_IN_TEMP_VDD                0x3
+#define ADT7316_LSB_IN_TEMP_MASK       0x3
+#define ADT7316_LSB_VDD_MASK           0xC
+#define ADT7316_LSB_VDD_OFFSET         2
+#define ADT7316_LSB_EX_TEMP_AIN                0x4
+#define ADT7316_LSB_EX_TEMP_MASK       0x3
+#define ADT7516_LSB_AIN_SHIFT          2
+#define ADT7316_AD_MSB_DATA_BASE        0x6
+#define ADT7316_AD_MSB_DATA_REGS        3
+#define ADT7516_AD_MSB_DATA_REGS        6
+#define ADT7316_MSB_VDD                        0x6
+#define ADT7316_MSB_IN_TEMP            0x7
+#define ADT7316_MSB_EX_TEMP            0x8
+#define ADT7516_MSB_AIN1               0x8
+#define ADT7516_MSB_AIN2               0x9
+#define ADT7516_MSB_AIN3               0xA
+#define ADT7516_MSB_AIN4               0xB
+#define ADT7316_DA_DATA_BASE           0x10
+#define ADT7316_DA_MSB_DATA_REGS       4
+#define ADT7316_LSB_DAC_A              0x10
+#define ADT7316_MSB_DAC_A              0x11
+#define ADT7316_LSB_DAC_B              0x12
+#define ADT7316_MSB_DAC_B              0x13
+#define ADT7316_LSB_DAC_C              0x14
+#define ADT7316_MSB_DAC_C              0x15
+#define ADT7316_LSB_DAC_D              0x16
+#define ADT7316_MSB_DAC_D              0x17
+#define ADT7316_CONFIG1                        0x18
+#define ADT7316_CONFIG2                        0x19
+#define ADT7316_CONFIG3                        0x1A
+#define ADT7316_LDAC_CONFIG            0x1B
+#define ADT7316_DAC_CONFIG             0x1C
+#define ADT7316_INT_MASK1              0x1D
+#define ADT7316_INT_MASK2              0x1E
+#define ADT7316_IN_TEMP_OFFSET         0x1F
+#define ADT7316_EX_TEMP_OFFSET         0x20
+#define ADT7316_IN_ANALOG_TEMP_OFFSET  0x21
+#define ADT7316_EX_ANALOG_TEMP_OFFSET  0x22
+#define ADT7316_VDD_HIGH               0x23
+#define ADT7316_VDD_LOW                        0x24
+#define ADT7316_IN_TEMP_HIGH           0x25
+#define ADT7316_IN_TEMP_LOW            0x26
+#define ADT7316_EX_TEMP_HIGH           0x27
+#define ADT7316_EX_TEMP_LOW            0x28
+#define ADT7516_AIN2_HIGH              0x2B
+#define ADT7516_AIN2_LOW               0x2C
+#define ADT7516_AIN3_HIGH              0x2D
+#define ADT7516_AIN3_LOW               0x2E
+#define ADT7516_AIN4_HIGH              0x2F
+#define ADT7516_AIN4_LOW               0x30
+#define ADT7316_DEVICE_ID              0x4D
+#define ADT7316_MANUFACTURE_ID         0x4E
+#define ADT7316_DEVICE_REV             0x4F
+#define ADT7316_SPI_LOCK_STAT          0x7F
+
+/*
+ * ADT7316 config1
+ */
+#define ADT7316_EN                     0x1
+#define ADT7516_SEL_EX_TEMP            0x4
+#define ADT7516_SEL_AIN1_2_EX_TEMP_MASK        0x6
+#define ADT7516_SEL_AIN3               0x8
+#define ADT7316_INT_EN                 0x20
+#define ADT7316_INT_POLARITY           0x40
+#define ADT7316_PD                     0x80
+
+/*
+ * ADT7316 config2
+ */
+#define ADT7316_AD_SINGLE_CH_MASK      0x3
+#define ADT7516_AD_SINGLE_CH_MASK      0x7
+#define ADT7316_AD_SINGLE_CH_VDD       0
+#define ADT7316_AD_SINGLE_CH_IN                1
+#define ADT7316_AD_SINGLE_CH_EX                2
+#define ADT7516_AD_SINGLE_CH_AIN1      2
+#define ADT7516_AD_SINGLE_CH_AIN2      3
+#define ADT7516_AD_SINGLE_CH_AIN3      4
+#define ADT7516_AD_SINGLE_CH_AIN4      5
+#define ADT7316_AD_SINGLE_CH_MODE      0x10
+#define ADT7316_DISABLE_AVERAGING      0x20
+#define ADT7316_EN_SMBUS_TIMEOUT       0x40
+#define ADT7316_RESET                  0x80
+
+/*
+ * ADT7316 config3
+ */
+#define ADT7316_ADCLK_22_5             0x1
+#define ADT7316_DA_HIGH_RESOLUTION     0x2
+#define ADT7316_DA_EN_VIA_DAC_LDCA     0x4
+#define ADT7516_AIN_IN_VREF            0x10
+#define ADT7316_EN_IN_TEMP_PROP_DACA   0x20
+#define ADT7316_EN_EX_TEMP_PROP_DACB   0x40
+
+/*
+ * ADT7316 DAC config
+ */
+#define ADT7316_DA_2VREF_CH_MASK       0xF
+#define ADT7316_DA_EN_MODE_MASK                0x30
+#define ADT7316_DA_EN_MODE_SINGLE      0x00
+#define ADT7316_DA_EN_MODE_AB_CD       0x10
+#define ADT7316_DA_EN_MODE_ABCD                0x20
+#define ADT7316_DA_EN_MODE_LDAC                0x30
+#define ADT7316_VREF_BYPASS_DAC_AB     0x40
+#define ADT7316_VREF_BYPASS_DAC_CD     0x80
+
+/*
+ * ADT7316 LDAC config
+ */
+#define ADT7316_LDAC_EN_DA_MASK                0xF
+#define ADT7316_DAC_IN_VREF            0x10
+#define ADT7516_DAC_AB_IN_VREF         0x10
+#define ADT7516_DAC_CD_IN_VREF         0x20
+#define ADT7516_DAC_IN_VREF_OFFSET     4
+#define ADT7516_DAC_IN_VREF_MASK       0x30
+
+/*
+ * ADT7316 INT_MASK2
+ */
+#define ADT7316_INT_MASK2_VDD          0x10
+
+/*
+ * ADT7316 value masks
+ */
+#define ADT7316_VALUE_MASK             0xfff
+#define ADT7316_T_VALUE_SIGN           0x400
+#define ADT7316_T_VALUE_FLOAT_OFFSET   2
+#define ADT7316_T_VALUE_FLOAT_MASK     0x2
+
+/*
+ * Chip ID
+ */
+#define ID_ADT7316             0x1
+#define ID_ADT7317             0x2
+#define ID_ADT7318             0x3
+#define ID_ADT7516             0x11
+#define ID_ADT7517             0x12
+#define ID_ADT7519             0x14
+
+#define ID_FAMILY_MASK         0xF0
+#define ID_ADT73XX             0x0
+#define ID_ADT75XX             0x10
+
+/*
+ * struct adt7316_chip_info - chip specifc information
+ */
+
+struct adt7316_chip_info {
+       const char              *name;
+       struct iio_dev          *indio_dev;
+       struct work_struct      thresh_work;
+       s64                     last_timestamp;
+       struct adt7316_bus      bus;
+       u16                     ldac_pin;
+       u16                     int_mask;       /* 0x2f */
+       u8                      config1;
+       u8                      config2;
+       u8                      config3;
+       u8                      dac_config;     /* DAC config */
+       u8                      ldac_config;    /* LDAC config */
+       u8                      dac_bits;       /* 8, 10, 12 */
+       u8                      id;             /* chip id */
+};
+
+/*
+ * Logic interrupt mask for user application to enable
+ * interrupts.
+ */
+#define ADT7316_IN_TEMP_HIGH_INT_MASK  0x1
+#define ADT7316_IN_TEMP_LOW_INT_MASK   0x2
+#define ADT7316_EX_TEMP_HIGH_INT_MASK  0x4
+#define ADT7316_EX_TEMP_LOW_INT_MASK   0x8
+#define ADT7316_EX_TEMP_FAULT_INT_MASK 0x10
+#define ADT7516_AIN1_INT_MASK          0x4
+#define ADT7516_AIN2_INT_MASK          0x20
+#define ADT7516_AIN3_INT_MASK          0x40
+#define ADT7516_AIN4_INT_MASK          0x80
+#define ADT7316_VDD_INT_MASK           0x100
+#define ADT7316_TEMP_INT_MASK          0x1F
+#define ADT7516_AIN_INT_MASK           0xE0
+#define ADT7316_TEMP_AIN_INT_MASK      \
+       (ADT7316_TEMP_INT_MASK | ADT7316_TEMP_INT_MASK)
+
+/*
+ * struct adt7316_chip_info - chip specifc information
+ */
+
+struct adt7316_limit_regs {
+       u16     data_high;
+       u16     data_low;
+};
+
+static ssize_t adt7316_show_enabled(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_EN));
+}
+
+static ssize_t _adt7316_store_enabled(struct adt7316_chip_info *chip,
+               int enable)
+{
+       u8 config1;
+       int ret;
+
+       if (enable)
+               config1 = chip->config1 | ADT7316_EN;
+       else
+               config1 = chip->config1 & ~ADT7316_EN;
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1);
+       if (ret)
+               return -EIO;
+
+       chip->config1 = config1;
+
+       return ret;
+
+}
+
+static ssize_t adt7316_store_enabled(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       int enable;
+
+       if (!memcmp(buf, "1", 1))
+               enable = 1;
+       else
+               enable = 0;
+
+       if (_adt7316_store_enabled(chip, enable) < 0)
+               return -EIO;
+       else
+               return len;
+}
+
+static IIO_DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR,
+               adt7316_show_enabled,
+               adt7316_store_enabled,
+               0);
+
+static ssize_t adt7316_show_select_ex_temp(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
+               return -EPERM;
+
+       return sprintf(buf, "%d\n", !!(chip->config1 & ADT7516_SEL_EX_TEMP));
+}
+
+static ssize_t adt7316_store_select_ex_temp(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 config1;
+       int ret;
+
+       if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
+               return -EPERM;
+
+       config1 = chip->config1 & (~ADT7516_SEL_EX_TEMP);
+       if (!memcmp(buf, "1", 1))
+               config1 |= ADT7516_SEL_EX_TEMP;
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1);
+       if (ret)
+               return -EIO;
+
+       chip->config1 = config1;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(select_ex_temp, S_IRUGO | S_IWUSR,
+               adt7316_show_select_ex_temp,
+               adt7316_store_select_ex_temp,
+               0);
+
+static ssize_t adt7316_show_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       if (chip->config2 & ADT7316_AD_SINGLE_CH_MODE)
+               return sprintf(buf, "single_channel\n");
+       else
+               return sprintf(buf, "round_robin\n");
+}
+
+static ssize_t adt7316_store_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 config2;
+       int ret;
+
+       config2 = chip->config2 & (~ADT7316_AD_SINGLE_CH_MODE);
+       if (!memcmp(buf, "single_channel", 14))
+               config2 |= ADT7316_AD_SINGLE_CH_MODE;
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
+       if (ret)
+               return -EIO;
+
+       chip->config2 = config2;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+               adt7316_show_mode,
+               adt7316_store_mode,
+               0);
+
+static ssize_t adt7316_show_all_modes(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return sprintf(buf, "single_channel\nround_robin\n");
+}
+
+static IIO_DEVICE_ATTR(all_modes, S_IRUGO, adt7316_show_all_modes, NULL, 0);
+
+static ssize_t adt7316_show_ad_channel(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE))
+               return -EPERM;
+
+       switch (chip->config2 & ADT7516_AD_SINGLE_CH_MASK) {
+       case ADT7316_AD_SINGLE_CH_VDD:
+               return sprintf(buf, "0 - VDD\n");
+       case ADT7316_AD_SINGLE_CH_IN:
+               return sprintf(buf, "1 - Internal Temperature\n");
+       case ADT7316_AD_SINGLE_CH_EX:
+               if (((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) &&
+                       (chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0)
+                       return sprintf(buf, "2 - AIN1\n");
+               else
+                       return sprintf(buf, "2 - External Temperature\n");
+       case ADT7516_AD_SINGLE_CH_AIN2:
+               if ((chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0)
+                       return sprintf(buf, "3 - AIN2\n");
+               else
+                       return sprintf(buf, "N/A\n");
+       case ADT7516_AD_SINGLE_CH_AIN3:
+               if (chip->config1 & ADT7516_SEL_AIN3)
+                       return sprintf(buf, "4 - AIN3\n");
+               else
+                       return sprintf(buf, "N/A\n");
+       case ADT7516_AD_SINGLE_CH_AIN4:
+               return sprintf(buf, "5 - AIN4\n");
+       default:
+               return sprintf(buf, "N/A\n");
+       };
+}
+
+static ssize_t adt7316_store_ad_channel(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 config2;
+       unsigned long data = 0;
+       int ret;
+
+       if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE))
+               return -EPERM;
+
+       ret = strict_strtoul(buf, 10, &data);
+       if (ret)
+               return -EINVAL;
+
+       if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) {
+               if (data > 5)
+                       return -EINVAL;
+
+               config2 = chip->config2 & (~ADT7516_AD_SINGLE_CH_MASK);
+       } else {
+               if (data > 2)
+                       return -EINVAL;
+
+               config2 = chip->config2 & (~ADT7316_AD_SINGLE_CH_MASK);
+       }
+
+
+       config2 |= data;
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
+       if (ret)
+               return -EIO;
+
+       chip->config2 = config2;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(ad_channel, S_IRUGO | S_IWUSR,
+               adt7316_show_ad_channel,
+               adt7316_store_ad_channel,
+               0);
+
+static ssize_t adt7316_show_all_ad_channels(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE))
+               return -EPERM;
+
+       if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+               return sprintf(buf, "0 - VDD\n1 - Internal Temperature\n"
+                               "2 - External Temperature or AIN2\n"
+                               "3 - AIN2\n4 - AIN3\n5 - AIN4\n");
+       else
+               return sprintf(buf, "0 - VDD\n1 - Internal Temperature\n"
+                               "2 - External Temperature\n");
+}
+
+static IIO_DEVICE_ATTR(all_ad_channels, S_IRUGO,
+               adt7316_show_all_ad_channels, NULL, 0);
+
+static ssize_t adt7316_show_disable_averaging(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n",
+               !!(chip->config2 & ADT7316_DISABLE_AVERAGING));
+}
+
+static ssize_t adt7316_store_disable_averaging(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 config2;
+       int ret;
+
+       config2 = chip->config2 & (~ADT7316_DISABLE_AVERAGING);
+       if (!memcmp(buf, "1", 1))
+               config2 |= ADT7316_DISABLE_AVERAGING;
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
+       if (ret)
+               return -EIO;
+
+       chip->config2 = config2;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(disable_averaging, S_IRUGO | S_IWUSR,
+               adt7316_show_disable_averaging,
+               adt7316_store_disable_averaging,
+               0);
+
+static ssize_t adt7316_show_enable_smbus_timeout(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n",
+               !!(chip->config2 & ADT7316_EN_SMBUS_TIMEOUT));
+}
+
+static ssize_t adt7316_store_enable_smbus_timeout(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 config2;
+       int ret;
+
+       config2 = chip->config2 & (~ADT7316_EN_SMBUS_TIMEOUT);
+       if (!memcmp(buf, "1", 1))
+               config2 |= ADT7316_EN_SMBUS_TIMEOUT;
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
+       if (ret)
+               return -EIO;
+
+       chip->config2 = config2;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(enable_smbus_timeout, S_IRUGO | S_IWUSR,
+               adt7316_show_enable_smbus_timeout,
+               adt7316_store_enable_smbus_timeout,
+               0);
+
+
+static ssize_t adt7316_store_reset(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 config2;
+       int ret;
+
+       config2 = chip->config2 | ADT7316_RESET;
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG2, config2);
+       if (ret)
+               return -EIO;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(reset, S_IWUSR,
+               NULL,
+               adt7316_store_reset,
+               0);
+
+static ssize_t adt7316_show_powerdown(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_PD));
+}
+
+static ssize_t adt7316_store_powerdown(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 config1;
+       int ret;
+
+       config1 = chip->config1 & (~ADT7316_PD);
+       if (!memcmp(buf, "1", 1))
+               config1 |= ADT7316_PD;
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1);
+       if (ret)
+               return -EIO;
+
+       chip->config1 = config1;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(powerdown, S_IRUGO | S_IWUSR,
+               adt7316_show_powerdown,
+               adt7316_store_powerdown,
+               0);
+
+static ssize_t adt7316_show_fast_ad_clock(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", !!(chip->config3 & ADT7316_ADCLK_22_5));
+}
+
+static ssize_t adt7316_store_fast_ad_clock(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 config3;
+       int ret;
+
+       config3 = chip->config3 & (~ADT7316_ADCLK_22_5);
+       if (!memcmp(buf, "1", 1))
+               config3 |= ADT7316_ADCLK_22_5;
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
+       if (ret)
+               return -EIO;
+
+       chip->config3 = config3;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(fast_ad_clock, S_IRUGO | S_IWUSR,
+               adt7316_show_fast_ad_clock,
+               adt7316_store_fast_ad_clock,
+               0);
+
+static ssize_t adt7316_show_da_high_resolution(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       if (chip->config3 & ADT7316_DA_HIGH_RESOLUTION) {
+               if (chip->id == ID_ADT7316 || chip->id == ID_ADT7516)
+                       return sprintf(buf, "1 (12 bits)\n");
+               else if (chip->id == ID_ADT7317 || chip->id == ID_ADT7517)
+                       return sprintf(buf, "1 (10 bits)\n");
+       }
+
+       return sprintf(buf, "0 (8 bits)\n");
+}
+
+static ssize_t adt7316_store_da_high_resolution(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 config3;
+       int ret;
+
+       chip->dac_bits = 8;
+
+       if (!memcmp(buf, "1", 1)) {
+               config3 = chip->config3 | ADT7316_DA_HIGH_RESOLUTION;
+               if (chip->id == ID_ADT7316 || chip->id == ID_ADT7516)
+                       chip->dac_bits = 12;
+               else if (chip->id == ID_ADT7317 || chip->id == ID_ADT7517)
+                       chip->dac_bits = 10;
+       } else
+               config3 = chip->config3 & (~ADT7316_DA_HIGH_RESOLUTION);
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
+       if (ret)
+               return -EIO;
+
+       chip->config3 = config3;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(da_high_resolution, S_IRUGO | S_IWUSR,
+               adt7316_show_da_high_resolution,
+               adt7316_store_da_high_resolution,
+               0);
+
+static ssize_t adt7316_show_AIN_internal_Vref(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
+               return -EPERM;
+
+       return sprintf(buf, "%d\n",
+               !!(chip->config3 & ADT7516_AIN_IN_VREF));
+}
+
+static ssize_t adt7316_store_AIN_internal_Vref(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 config3;
+       int ret;
+
+       if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
+               return -EPERM;
+
+       if (memcmp(buf, "1", 1))
+               config3 = chip->config3 & (~ADT7516_AIN_IN_VREF);
+       else
+               config3 = chip->config3 | ADT7516_AIN_IN_VREF;
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
+       if (ret)
+               return -EIO;
+
+       chip->config3 = config3;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(AIN_internal_Vref, S_IRUGO | S_IWUSR,
+               adt7316_show_AIN_internal_Vref,
+               adt7316_store_AIN_internal_Vref,
+               0);
+
+
+static ssize_t adt7316_show_enable_prop_DACA(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n",
+               !!(chip->config3 & ADT7316_EN_IN_TEMP_PROP_DACA));
+}
+
+static ssize_t adt7316_store_enable_prop_DACA(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 config3;
+       int ret;
+
+       config3 = chip->config3 & (~ADT7316_EN_IN_TEMP_PROP_DACA);
+       if (!memcmp(buf, "1", 1))
+               config3 |= ADT7316_EN_IN_TEMP_PROP_DACA;
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
+       if (ret)
+               return -EIO;
+
+       chip->config3 = config3;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(enable_proportion_DACA, S_IRUGO | S_IWUSR,
+               adt7316_show_enable_prop_DACA,
+               adt7316_store_enable_prop_DACA,
+               0);
+
+static ssize_t adt7316_show_enable_prop_DACB(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n",
+               !!(chip->config3 & ADT7316_EN_EX_TEMP_PROP_DACB));
+}
+
+static ssize_t adt7316_store_enable_prop_DACB(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 config3;
+       int ret;
+
+       config3 = chip->config3 & (~ADT7316_EN_EX_TEMP_PROP_DACB);
+       if (!memcmp(buf, "1", 1))
+               config3 |= ADT7316_EN_EX_TEMP_PROP_DACB;
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
+       if (ret)
+               return -EIO;
+
+       chip->config3 = config3;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(enable_proportion_DACB, S_IRUGO | S_IWUSR,
+               adt7316_show_enable_prop_DACB,
+               adt7316_store_enable_prop_DACB,
+               0);
+
+static ssize_t adt7316_show_DAC_2Vref_ch_mask(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "0x%x\n",
+               chip->dac_config & ADT7316_DA_2VREF_CH_MASK);
+}
+
+static ssize_t adt7316_store_DAC_2Vref_ch_mask(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 dac_config;
+       unsigned long data = 0;
+       int ret;
+
+       ret = strict_strtoul(buf, 16, &data);
+       if (ret || data > ADT7316_DA_2VREF_CH_MASK)
+               return -EINVAL;
+
+       dac_config = chip->dac_config & (~ADT7316_DA_2VREF_CH_MASK);
+       dac_config |= data;
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config);
+       if (ret)
+               return -EIO;
+
+       chip->dac_config = dac_config;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(DAC_2Vref_channels_mask, S_IRUGO | S_IWUSR,
+               adt7316_show_DAC_2Vref_ch_mask,
+               adt7316_store_DAC_2Vref_ch_mask,
+               0);
+
+static ssize_t adt7316_show_DAC_update_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA))
+               return sprintf(buf, "manual\n");
+       else {
+               switch (chip->dac_config & ADT7316_DA_EN_MODE_MASK) {
+               case ADT7316_DA_EN_MODE_SINGLE:
+                       return sprintf(buf, "0 - auto at any MSB DAC writing\n");
+               case ADT7316_DA_EN_MODE_AB_CD:
+                       return sprintf(buf, "1 - auto at MSB DAC AB and CD writing\n");
+               case ADT7316_DA_EN_MODE_ABCD:
+                       return sprintf(buf, "2 - auto at MSB DAC ABCD writing\n");
+               default: /* ADT7316_DA_EN_MODE_LDAC */
+                       return sprintf(buf, "3 - manual\n");
+               };
+       }
+}
+
+static ssize_t adt7316_store_DAC_update_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 dac_config;
+       unsigned long data;
+       int ret;
+
+       if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA))
+               return -EPERM;
+
+       ret = strict_strtoul(buf, 10, &data);
+       if (ret || data > ADT7316_DA_EN_MODE_MASK)
+               return -EINVAL;
+
+       dac_config = chip->dac_config & (~ADT7316_DA_EN_MODE_MASK);
+       dac_config |= data;
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config);
+       if (ret)
+               return -EIO;
+
+       chip->dac_config = dac_config;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(DAC_update_mode, S_IRUGO | S_IWUSR,
+               adt7316_show_DAC_update_mode,
+               adt7316_store_DAC_update_mode,
+               0);
+
+static ssize_t adt7316_show_all_DAC_update_modes(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA)
+               return sprintf(buf, "0 - auto at any MSB DAC writing\n"
+                               "1 - auto at MSB DAC AB and CD writing\n"
+                               "2 - auto at MSB DAC ABCD writing\n"
+                               "3 - manual\n");
+       else
+               return sprintf(buf, "manual\n");
+}
+
+static IIO_DEVICE_ATTR(all_DAC_update_modes, S_IRUGO,
+               adt7316_show_all_DAC_update_modes, NULL, 0);
+
+
+static ssize_t adt7316_store_update_DAC(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 ldac_config;
+       unsigned long data;
+       int ret;
+
+       if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA) {
+               if ((chip->dac_config & ADT7316_DA_EN_MODE_MASK) !=
+                       ADT7316_DA_EN_MODE_LDAC)
+                       return -EPERM;
+
+               ret = strict_strtoul(buf, 16, &data);
+               if (ret || data > ADT7316_LDAC_EN_DA_MASK)
+                       return -EINVAL;
+
+               ldac_config = chip->ldac_config & (~ADT7316_LDAC_EN_DA_MASK);
+               ldac_config |= data;
+
+               ret = chip->bus.write(chip->bus.client, ADT7316_LDAC_CONFIG,
+                       ldac_config);
+               if (ret)
+                       return -EIO;
+       } else {
+               gpio_set_value(chip->ldac_pin, 0);
+               gpio_set_value(chip->ldac_pin, 1);
+       }
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(update_DAC, S_IRUGO | S_IWUSR,
+               NULL,
+               adt7316_store_update_DAC,
+               0);
+
+static ssize_t adt7316_show_DA_AB_Vref_bypass(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+               return -EPERM;
+
+       return sprintf(buf, "%d\n",
+               !!(chip->dac_config & ADT7316_VREF_BYPASS_DAC_AB));
+}
+
+static ssize_t adt7316_store_DA_AB_Vref_bypass(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 dac_config;
+       int ret;
+
+       if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+               return -EPERM;
+
+       dac_config = chip->dac_config & (~ADT7316_VREF_BYPASS_DAC_AB);
+       if (!memcmp(buf, "1", 1))
+               dac_config |= ADT7316_VREF_BYPASS_DAC_AB;
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config);
+       if (ret)
+               return -EIO;
+
+       chip->dac_config = dac_config;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(DA_AB_Vref_bypass, S_IRUGO | S_IWUSR,
+               adt7316_show_DA_AB_Vref_bypass,
+               adt7316_store_DA_AB_Vref_bypass,
+               0);
+
+static ssize_t adt7316_show_DA_CD_Vref_bypass(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+               return -EPERM;
+
+       return sprintf(buf, "%d\n",
+               !!(chip->dac_config & ADT7316_VREF_BYPASS_DAC_CD));
+}
+
+static ssize_t adt7316_store_DA_CD_Vref_bypass(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 dac_config;
+       int ret;
+
+       if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+               return -EPERM;
+
+       dac_config = chip->dac_config & (~ADT7316_VREF_BYPASS_DAC_CD);
+       if (!memcmp(buf, "1", 1))
+               dac_config |= ADT7316_VREF_BYPASS_DAC_CD;
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_DAC_CONFIG, dac_config);
+       if (ret)
+               return -EIO;
+
+       chip->dac_config = dac_config;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(DA_CD_Vref_bypass, S_IRUGO | S_IWUSR,
+               adt7316_show_DA_CD_Vref_bypass,
+               adt7316_store_DA_CD_Vref_bypass,
+               0);
+
+static ssize_t adt7316_show_DAC_internal_Vref(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+               return sprintf(buf, "0x%x\n",
+                       (chip->dac_config & ADT7516_DAC_IN_VREF_MASK) >>
+                       ADT7516_DAC_IN_VREF_OFFSET);
+       else
+               return sprintf(buf, "%d\n",
+                       !!(chip->dac_config & ADT7316_DAC_IN_VREF));
+}
+
+static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 ldac_config;
+       unsigned long data;
+       int ret;
+
+       if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) {
+               ret = strict_strtoul(buf, 16, &data);
+               if (ret || data > 3)
+                       return -EINVAL;
+
+               ldac_config = chip->ldac_config & (~ADT7516_DAC_IN_VREF_MASK);
+               if (data & 0x1)
+                       ldac_config |= ADT7516_DAC_AB_IN_VREF;
+               else if (data & 0x2)
+                       ldac_config |= ADT7516_DAC_CD_IN_VREF;
+       } else {
+               ret = strict_strtoul(buf, 16, &data);
+               if (ret)
+                       return -EINVAL;
+
+               ldac_config = chip->ldac_config & (~ADT7316_DAC_IN_VREF);
+               if (data)
+                       ldac_config = chip->ldac_config | ADT7316_DAC_IN_VREF;
+       }
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_LDAC_CONFIG, ldac_config);
+       if (ret)
+               return -EIO;
+
+       chip->ldac_config = ldac_config;
+
+       return len;
+}
+
+static IIO_DEVICE_ATTR(DAC_internal_Vref, S_IRUGO | S_IWUSR,
+               adt7316_show_DAC_internal_Vref,
+               adt7316_store_DAC_internal_Vref,
+               0);
+
+static ssize_t adt7316_show_ad(struct adt7316_chip_info *chip,
+               int channel, char *buf)
+{
+       u16 data;
+       u8 msb, lsb;
+       char sign = ' ';
+       int ret;
+
+       if ((chip->config2 & ADT7316_AD_SINGLE_CH_MODE) &&
+               channel != (chip->config2 & ADT7516_AD_SINGLE_CH_MASK))
+               return -EPERM;
+
+       switch (channel) {
+       case ADT7316_AD_SINGLE_CH_IN:
+               ret = chip->bus.read(chip->bus.client,
+                       ADT7316_LSB_IN_TEMP_VDD, &lsb);
+               if (ret)
+                       return -EIO;
+
+               ret = chip->bus.read(chip->bus.client,
+                       ADT7316_AD_MSB_DATA_BASE + channel, &msb);
+               if (ret)
+                       return -EIO;
+
+               data = msb << ADT7316_T_VALUE_FLOAT_OFFSET;
+               data |= lsb & ADT7316_LSB_IN_TEMP_MASK;
+               break;
+       case ADT7316_AD_SINGLE_CH_VDD:
+               ret = chip->bus.read(chip->bus.client,
+                       ADT7316_LSB_IN_TEMP_VDD, &lsb);
+               if (ret)
+                       return -EIO;
+
+               ret = chip->bus.read(chip->bus.client,
+
+                       ADT7316_AD_MSB_DATA_BASE + channel, &msb);
+               if (ret)
+                       return -EIO;
+
+               data = msb << ADT7316_T_VALUE_FLOAT_OFFSET;
+               data |= (lsb & ADT7316_LSB_VDD_MASK) >> ADT7316_LSB_VDD_OFFSET;
+               return sprintf(buf, "%d\n", data);
+       default: /* ex_temp and ain */
+               ret = chip->bus.read(chip->bus.client,
+                       ADT7316_LSB_EX_TEMP_AIN, &lsb);
+               if (ret)
+                       return -EIO;
+
+               ret = chip->bus.read(chip->bus.client,
+                       ADT7316_AD_MSB_DATA_BASE + channel, &msb);
+               if (ret)
+                       return -EIO;
+
+               data = msb << ADT7316_T_VALUE_FLOAT_OFFSET;
+               data |= lsb & (ADT7316_LSB_EX_TEMP_MASK <<
+                       (ADT7516_LSB_AIN_SHIFT * (channel -
+                       (ADT7316_MSB_EX_TEMP - ADT7316_AD_MSB_DATA_BASE))));
+
+               if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+                       return sprintf(buf, "%d\n", data);
+               else
+                       break;
+       };
+
+       if (data & ADT7316_T_VALUE_SIGN) {
+               /* convert supplement to positive value */
+               data = (ADT7316_T_VALUE_SIGN << 1) - data;
+               sign = '-';
+       }
+
+       return sprintf(buf, "%c%d.%.2d\n", sign,
+               (data >> ADT7316_T_VALUE_FLOAT_OFFSET),
+               (data & ADT7316_T_VALUE_FLOAT_MASK) * 25);
+}
+
+static ssize_t adt7316_show_VDD(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_VDD, buf);
+}
+static IIO_DEVICE_ATTR(VDD, S_IRUGO, adt7316_show_VDD, NULL, 0);
+
+static ssize_t adt7316_show_in_temp(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_IN, buf);
+}
+
+static IIO_DEVICE_ATTR(in_temp, S_IRUGO, adt7316_show_in_temp, NULL, 0);
+
+static ssize_t adt7316_show_ex_temp_AIN1(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_EX, buf);
+}
+
+static IIO_DEVICE_ATTR(ex_temp_AIN1, S_IRUGO, adt7316_show_ex_temp_AIN1, NULL, 0);
+static IIO_DEVICE_ATTR(ex_temp, S_IRUGO, adt7316_show_ex_temp_AIN1, NULL, 0);
+
+static ssize_t adt7316_show_AIN2(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN2, buf);
+}
+static IIO_DEVICE_ATTR(AIN2, S_IRUGO, adt7316_show_AIN2, NULL, 0);
+
+static ssize_t adt7316_show_AIN3(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN3, buf);
+}
+static IIO_DEVICE_ATTR(AIN3, S_IRUGO, adt7316_show_AIN3, NULL, 0);
+
+static ssize_t adt7316_show_AIN4(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN4, buf);
+}
+static IIO_DEVICE_ATTR(AIN4, S_IRUGO, adt7316_show_AIN4, NULL, 0);
+
+static ssize_t adt7316_show_temp_offset(struct adt7316_chip_info *chip,
+               int offset_addr, char *buf)
+{
+       int data;
+       u8 val;
+       int ret;
+
+       ret = chip->bus.read(chip->bus.client, offset_addr, &val);
+       if (ret)
+               return -EIO;
+
+       data = (int)val;
+       if (val & 0x80)
+               data -= 256;
+
+       return sprintf(buf, "%d\n", data);
+}
+
+static ssize_t adt7316_store_temp_offset(struct adt7316_chip_info *chip,
+               int offset_addr, const char *buf, size_t len)
+{
+       long data;
+       u8 val;
+       int ret;
+
+       ret = strict_strtol(buf, 10, &data);
+       if (ret || data > 127 || data < -128)
+               return -EINVAL;
+
+       if (data < 0)
+               data += 256;
+
+       val = (u8)data;
+
+       ret = chip->bus.write(chip->bus.client, offset_addr, val);
+       if (ret)
+               return -EIO;
+
+       return len;
+}
+
+static ssize_t adt7316_show_in_temp_offset(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_show_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf);
+}
+
+static ssize_t adt7316_store_in_temp_offset(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_store_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf, len);
+}
+
+static IIO_DEVICE_ATTR(in_temp_offset, S_IRUGO | S_IWUSR,
+               adt7316_show_in_temp_offset,
+               adt7316_store_in_temp_offset, 0);
+
+static ssize_t adt7316_show_ex_temp_offset(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_show_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf);
+}
+
+static ssize_t adt7316_store_ex_temp_offset(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_store_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf, len);
+}
+
+static IIO_DEVICE_ATTR(ex_temp_offset, S_IRUGO | S_IWUSR,
+               adt7316_show_ex_temp_offset,
+               adt7316_store_ex_temp_offset, 0);
+
+static ssize_t adt7316_show_in_analog_temp_offset(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_show_temp_offset(chip,
+                       ADT7316_IN_ANALOG_TEMP_OFFSET, buf);
+}
+
+static ssize_t adt7316_store_in_analog_temp_offset(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_store_temp_offset(chip,
+                       ADT7316_IN_ANALOG_TEMP_OFFSET, buf, len);
+}
+
+static IIO_DEVICE_ATTR(in_analog_temp_offset, S_IRUGO | S_IWUSR,
+               adt7316_show_in_analog_temp_offset,
+               adt7316_store_in_analog_temp_offset, 0);
+
+static ssize_t adt7316_show_ex_analog_temp_offset(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_show_temp_offset(chip,
+                       ADT7316_EX_ANALOG_TEMP_OFFSET, buf);
+}
+
+static ssize_t adt7316_store_ex_analog_temp_offset(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_store_temp_offset(chip,
+                       ADT7316_EX_ANALOG_TEMP_OFFSET, buf, len);
+}
+
+static IIO_DEVICE_ATTR(ex_analog_temp_offset, S_IRUGO | S_IWUSR,
+               adt7316_show_ex_analog_temp_offset,
+               adt7316_store_ex_analog_temp_offset, 0);
+
+static ssize_t adt7316_show_DAC(struct adt7316_chip_info *chip,
+               int channel, char *buf)
+{
+       u16 data;
+       u8 msb, lsb, offset;
+       int ret;
+
+       if (channel >= ADT7316_DA_MSB_DATA_REGS ||
+               (channel == 0 &&
+               (chip->config3 & ADT7316_EN_IN_TEMP_PROP_DACA)) ||
+               (channel == 1 &&
+               (chip->config3 & ADT7316_EN_EX_TEMP_PROP_DACB)))
+               return -EPERM;
+
+       offset = chip->dac_bits - 8;
+
+       if (chip->dac_bits > 8) {
+               ret = chip->bus.read(chip->bus.client,
+                       ADT7316_DA_DATA_BASE + channel * 2, &lsb);
+               if (ret)
+                       return -EIO;
+       }
+
+       ret = chip->bus.read(chip->bus.client,
+               ADT7316_DA_DATA_BASE + 1 + channel * 2, &msb);
+       if (ret)
+               return -EIO;
+
+       data = (msb << offset) + (lsb & ((1 << offset) - 1));
+
+       return sprintf(buf, "%d\n", data);
+}
+
+static ssize_t adt7316_store_DAC(struct adt7316_chip_info *chip,
+               int channel, const char *buf, size_t len)
+{
+       u8 msb, lsb, offset;
+       unsigned long data;
+       int ret;
+
+       if (channel >= ADT7316_DA_MSB_DATA_REGS ||
+               (channel == 0 &&
+               (chip->config3 & ADT7316_EN_IN_TEMP_PROP_DACA)) ||
+               (channel == 1 &&
+               (chip->config3 & ADT7316_EN_EX_TEMP_PROP_DACB)))
+               return -EPERM;
+
+       offset = chip->dac_bits - 8;
+
+       ret = strict_strtoul(buf, 10, &data);
+       if (ret || data >= (1 << chip->dac_bits))
+               return -EINVAL;
+
+       if (chip->dac_bits > 8) {
+               lsb = data & (1 << offset);
+               ret = chip->bus.write(chip->bus.client,
+                       ADT7316_DA_DATA_BASE + channel * 2, lsb);
+               if (ret)
+                       return -EIO;
+       }
+
+       msb = data >> offset;
+       ret = chip->bus.write(chip->bus.client,
+               ADT7316_DA_DATA_BASE + 1 + channel * 2, msb);
+       if (ret)
+               return -EIO;
+
+       return len;
+}
+
+static ssize_t adt7316_show_DAC_A(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_show_DAC(chip, 0, buf);
+}
+
+static ssize_t adt7316_store_DAC_A(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_store_DAC(chip, 0, buf, len);
+}
+
+static IIO_DEVICE_ATTR(DAC_A, S_IRUGO | S_IWUSR, adt7316_show_DAC_A,
+               adt7316_store_DAC_A, 0);
+
+static ssize_t adt7316_show_DAC_B(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_show_DAC(chip, 1, buf);
+}
+
+static ssize_t adt7316_store_DAC_B(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_store_DAC(chip, 1, buf, len);
+}
+
+static IIO_DEVICE_ATTR(DAC_B, S_IRUGO | S_IWUSR, adt7316_show_DAC_B,
+               adt7316_store_DAC_B, 0);
+
+static ssize_t adt7316_show_DAC_C(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_show_DAC(chip, 2, buf);
+}
+
+static ssize_t adt7316_store_DAC_C(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_store_DAC(chip, 2, buf, len);
+}
+
+static IIO_DEVICE_ATTR(DAC_C, S_IRUGO | S_IWUSR, adt7316_show_DAC_C,
+               adt7316_store_DAC_C, 0);
+
+static ssize_t adt7316_show_DAC_D(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_show_DAC(chip, 3, buf);
+}
+
+static ssize_t adt7316_store_DAC_D(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return adt7316_store_DAC(chip, 3, buf, len);
+}
+
+static IIO_DEVICE_ATTR(DAC_D, S_IRUGO | S_IWUSR, adt7316_show_DAC_D,
+               adt7316_store_DAC_D, 0);
+
+static ssize_t adt7316_show_device_id(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 id;
+       int ret;
+
+       ret = chip->bus.read(chip->bus.client, ADT7316_DEVICE_ID, &id);
+       if (ret)
+               return -EIO;
+
+       return sprintf(buf, "%d\n", id);
+}
+
+static IIO_DEVICE_ATTR(device_id, S_IRUGO, adt7316_show_device_id, NULL, 0);
+
+static ssize_t adt7316_show_manufactorer_id(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 id;
+       int ret;
+
+       ret = chip->bus.read(chip->bus.client, ADT7316_MANUFACTURE_ID, &id);
+       if (ret)
+               return -EIO;
+
+       return sprintf(buf, "%d\n", id);
+}
+
+static IIO_DEVICE_ATTR(manufactorer_id, S_IRUGO,
+               adt7316_show_manufactorer_id, NULL, 0);
+
+static ssize_t adt7316_show_device_rev(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 rev;
+       int ret;
+
+       ret = chip->bus.read(chip->bus.client, ADT7316_DEVICE_REV, &rev);
+       if (ret)
+               return -EIO;
+
+       return sprintf(buf, "%d\n", rev);
+}
+
+static IIO_DEVICE_ATTR(device_rev, S_IRUGO, adt7316_show_device_rev, NULL, 0);
+
+static ssize_t adt7316_show_bus_type(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 stat;
+       int ret;
+
+       ret = chip->bus.read(chip->bus.client, ADT7316_SPI_LOCK_STAT, &stat);
+       if (ret)
+               return -EIO;
+
+       if (stat)
+               return sprintf(buf, "spi\n");
+       else
+               return sprintf(buf, "i2c\n");
+}
+
+static IIO_DEVICE_ATTR(bus_type, S_IRUGO, adt7316_show_bus_type, NULL, 0);
+
+static ssize_t adt7316_show_name(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%s\n", chip->name);
+}
+
+static IIO_DEVICE_ATTR(name, S_IRUGO, adt7316_show_name, NULL, 0);
+
+static struct attribute *adt7316_attributes[] = {
+       &iio_dev_attr_all_modes.dev_attr.attr,
+       &iio_dev_attr_mode.dev_attr.attr,
+       &iio_dev_attr_reset.dev_attr.attr,
+       &iio_dev_attr_enabled.dev_attr.attr,
+       &iio_dev_attr_ad_channel.dev_attr.attr,
+       &iio_dev_attr_all_ad_channels.dev_attr.attr,
+       &iio_dev_attr_disable_averaging.dev_attr.attr,
+       &iio_dev_attr_enable_smbus_timeout.dev_attr.attr,
+       &iio_dev_attr_powerdown.dev_attr.attr,
+       &iio_dev_attr_fast_ad_clock.dev_attr.attr,
+       &iio_dev_attr_da_high_resolution.dev_attr.attr,
+       &iio_dev_attr_enable_proportion_DACA.dev_attr.attr,
+       &iio_dev_attr_enable_proportion_DACB.dev_attr.attr,
+       &iio_dev_attr_DAC_2Vref_channels_mask.dev_attr.attr,
+       &iio_dev_attr_DAC_update_mode.dev_attr.attr,
+       &iio_dev_attr_all_DAC_update_modes.dev_attr.attr,
+       &iio_dev_attr_update_DAC.dev_attr.attr,
+       &iio_dev_attr_DA_AB_Vref_bypass.dev_attr.attr,
+       &iio_dev_attr_DA_CD_Vref_bypass.dev_attr.attr,
+       &iio_dev_attr_DAC_internal_Vref.dev_attr.attr,
+       &iio_dev_attr_VDD.dev_attr.attr,
+       &iio_dev_attr_in_temp.dev_attr.attr,
+       &iio_dev_attr_ex_temp.dev_attr.attr,
+       &iio_dev_attr_in_temp_offset.dev_attr.attr,
+       &iio_dev_attr_ex_temp_offset.dev_attr.attr,
+       &iio_dev_attr_in_analog_temp_offset.dev_attr.attr,
+       &iio_dev_attr_ex_analog_temp_offset.dev_attr.attr,
+       &iio_dev_attr_DAC_A.dev_attr.attr,
+       &iio_dev_attr_DAC_B.dev_attr.attr,
+       &iio_dev_attr_DAC_C.dev_attr.attr,
+       &iio_dev_attr_DAC_D.dev_attr.attr,
+       &iio_dev_attr_device_id.dev_attr.attr,
+       &iio_dev_attr_manufactorer_id.dev_attr.attr,
+       &iio_dev_attr_device_rev.dev_attr.attr,
+       &iio_dev_attr_bus_type.dev_attr.attr,
+       &iio_dev_attr_name.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group adt7316_attribute_group = {
+       .attrs = adt7316_attributes,
+};
+
+static struct attribute *adt7516_attributes[] = {
+       &iio_dev_attr_all_modes.dev_attr.attr,
+       &iio_dev_attr_mode.dev_attr.attr,
+       &iio_dev_attr_select_ex_temp.dev_attr.attr,
+       &iio_dev_attr_reset.dev_attr.attr,
+       &iio_dev_attr_enabled.dev_attr.attr,
+       &iio_dev_attr_ad_channel.dev_attr.attr,
+       &iio_dev_attr_all_ad_channels.dev_attr.attr,
+       &iio_dev_attr_disable_averaging.dev_attr.attr,
+       &iio_dev_attr_enable_smbus_timeout.dev_attr.attr,
+       &iio_dev_attr_powerdown.dev_attr.attr,
+       &iio_dev_attr_fast_ad_clock.dev_attr.attr,
+       &iio_dev_attr_AIN_internal_Vref.dev_attr.attr,
+       &iio_dev_attr_da_high_resolution.dev_attr.attr,
+       &iio_dev_attr_enable_proportion_DACA.dev_attr.attr,
+       &iio_dev_attr_enable_proportion_DACB.dev_attr.attr,
+       &iio_dev_attr_DAC_2Vref_channels_mask.dev_attr.attr,
+       &iio_dev_attr_DAC_update_mode.dev_attr.attr,
+       &iio_dev_attr_all_DAC_update_modes.dev_attr.attr,
+       &iio_dev_attr_update_DAC.dev_attr.attr,
+       &iio_dev_attr_DA_AB_Vref_bypass.dev_attr.attr,
+       &iio_dev_attr_DA_CD_Vref_bypass.dev_attr.attr,
+       &iio_dev_attr_DAC_internal_Vref.dev_attr.attr,
+       &iio_dev_attr_VDD.dev_attr.attr,
+       &iio_dev_attr_in_temp.dev_attr.attr,
+       &iio_dev_attr_ex_temp_AIN1.dev_attr.attr,
+       &iio_dev_attr_AIN2.dev_attr.attr,
+       &iio_dev_attr_AIN3.dev_attr.attr,
+       &iio_dev_attr_AIN4.dev_attr.attr,
+       &iio_dev_attr_in_temp_offset.dev_attr.attr,
+       &iio_dev_attr_ex_temp_offset.dev_attr.attr,
+       &iio_dev_attr_in_analog_temp_offset.dev_attr.attr,
+       &iio_dev_attr_ex_analog_temp_offset.dev_attr.attr,
+       &iio_dev_attr_DAC_A.dev_attr.attr,
+       &iio_dev_attr_DAC_B.dev_attr.attr,
+       &iio_dev_attr_DAC_C.dev_attr.attr,
+       &iio_dev_attr_DAC_D.dev_attr.attr,
+       &iio_dev_attr_device_id.dev_attr.attr,
+       &iio_dev_attr_manufactorer_id.dev_attr.attr,
+       &iio_dev_attr_device_rev.dev_attr.attr,
+       &iio_dev_attr_bus_type.dev_attr.attr,
+       &iio_dev_attr_name.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group adt7516_attribute_group = {
+       .attrs = adt7516_attributes,
+};
+
+
+/*
+ * temperature bound events
+ */
+
+#define IIO_EVENT_CODE_ADT7316_IN_TEMP_HIGH   IIO_BUFFER_EVENT_CODE(0)
+#define IIO_EVENT_CODE_ADT7316_IN_TEMP_LOW    IIO_BUFFER_EVENT_CODE(1)
+#define IIO_EVENT_CODE_ADT7316_EX_TEMP_HIGH   IIO_BUFFER_EVENT_CODE(2)
+#define IIO_EVENT_CODE_ADT7316_EX_TEMP_LOW    IIO_BUFFER_EVENT_CODE(3)
+#define IIO_EVENT_CODE_ADT7316_EX_TEMP_FAULT  IIO_BUFFER_EVENT_CODE(4)
+#define IIO_EVENT_CODE_ADT7516_AIN1           IIO_BUFFER_EVENT_CODE(5)
+#define IIO_EVENT_CODE_ADT7516_AIN2           IIO_BUFFER_EVENT_CODE(6)
+#define IIO_EVENT_CODE_ADT7516_AIN3           IIO_BUFFER_EVENT_CODE(7)
+#define IIO_EVENT_CODE_ADT7516_AIN4           IIO_BUFFER_EVENT_CODE(8)
+#define IIO_EVENT_CODE_ADT7316_VDD            IIO_BUFFER_EVENT_CODE(9)
+
+static void adt7316_interrupt_bh(struct work_struct *work_s)
+{
+       struct adt7316_chip_info *chip =
+               container_of(work_s, struct adt7316_chip_info, thresh_work);
+       u8 stat1, stat2;
+       int i, ret, count;
+
+       ret = chip->bus.read(chip->bus.client, ADT7316_INT_STAT1, &stat1);
+       if (!ret) {
+               if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+                       count = 8;
+               else
+                       count = 5;
+
+               for (i = 0; i < count; i++) {
+                       if (stat1 & (1 << i))
+                               iio_push_event(chip->indio_dev, 0,
+                                       IIO_EVENT_CODE_ADT7316_IN_TEMP_HIGH + i,
+                                       chip->last_timestamp);
+               }
+       }
+
+       ret = chip->bus.read(chip->bus.client, ADT7316_INT_STAT2, &stat2);
+       if (!ret) {
+               if (stat2 & ADT7316_INT_MASK2_VDD)
+                       iio_push_event(chip->indio_dev, 0,
+                               IIO_EVENT_CODE_ADT7316_VDD,
+                               chip->last_timestamp);
+       }
+
+       enable_irq(chip->bus.irq);
+}
+
+static int adt7316_interrupt(struct iio_dev *dev_info,
+               int index,
+               s64 timestamp,
+               int no_test)
+{
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       chip->last_timestamp = timestamp;
+       schedule_work(&chip->thresh_work);
+
+       return 0;
+}
+
+IIO_EVENT_SH(adt7316, &adt7316_interrupt);
+
+/*
+ * Show mask of enabled interrupts in Hex.
+ */
+static ssize_t adt7316_show_int_mask(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "0x%x\n", chip->int_mask);
+}
+
+/*
+ * Set 1 to the mask in Hex to enabled interrupts.
+ */
+static ssize_t adt7316_set_int_mask(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       unsigned long data;
+       int ret;
+       u8 mask;
+
+       ret = strict_strtoul(buf, 16, &data);
+       if (ret || data >= ADT7316_VDD_INT_MASK + 1)
+               return -EINVAL;
+
+       if (data & ADT7316_VDD_INT_MASK)
+               mask = 0;                       /* enable vdd int */
+       else
+               mask = ADT7316_INT_MASK2_VDD;   /* disable vdd int */
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_INT_MASK2, mask);
+       if (!ret) {
+               chip->int_mask &= ~ADT7316_VDD_INT_MASK;
+               chip->int_mask |= data & ADT7316_VDD_INT_MASK;
+       }
+
+       if (data & ADT7316_TEMP_AIN_INT_MASK) {
+               if ((chip->id & ID_FAMILY_MASK) == ID_ADT73XX)
+                       /* mask in reg is opposite, set 1 to disable */
+                       mask = (~data) & ADT7316_TEMP_INT_MASK;
+               else
+                       /* mask in reg is opposite, set 1 to disable */
+                       mask = (~data) & ADT7316_TEMP_AIN_INT_MASK;
+       }
+       ret = chip->bus.write(chip->bus.client, ADT7316_INT_MASK1, mask);
+
+       chip->int_mask = mask;
+
+       return len;
+}
+static inline ssize_t adt7316_show_ad_bound(struct device *dev,
+               struct device_attribute *attr,
+               u8 bound_reg,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 val;
+       int data;
+       int ret;
+
+       if ((chip->id & ID_FAMILY_MASK) == ID_ADT73XX &&
+               bound_reg > ADT7316_EX_TEMP_LOW)
+               return -EPERM;
+
+       ret = chip->bus.read(chip->bus.client, bound_reg, &val);
+       if (ret)
+               return -EIO;
+
+       data = (int)val;
+
+       if (!((chip->id & ID_FAMILY_MASK) == ID_ADT75XX &&
+               (chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0)) {
+               if (data & 0x80)
+                       data -= 256;
+       }
+
+       return sprintf(buf, "%d\n", data);
+}
+
+static inline ssize_t adt7316_set_ad_bound(struct device *dev,
+               struct device_attribute *attr,
+               u8 bound_reg,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       long data;
+       u8 val;
+       int ret;
+
+       if ((chip->id & ID_FAMILY_MASK) == ID_ADT73XX &&
+               bound_reg > ADT7316_EX_TEMP_LOW)
+               return -EPERM;
+
+       ret = strict_strtol(buf, 10, &data);
+       if (ret)
+               return -EINVAL;
+
+       if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX &&
+               (chip->config1 & ADT7516_SEL_AIN1_2_EX_TEMP_MASK) == 0) {
+               if (data > 255 || data < 0)
+                       return -EINVAL;
+       } else {
+               if (data > 127 || data < -128)
+                       return -EINVAL;
+
+               if (data < 0)
+                       data += 256;
+       }
+
+       val = (u8)data;
+
+       ret = chip->bus.write(chip->bus.client, bound_reg, val);
+       if (ret)
+               return -EIO;
+
+       return len;
+}
+
+static ssize_t adt7316_show_in_temp_high(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return adt7316_show_ad_bound(dev, attr,
+                       ADT7316_IN_TEMP_HIGH, buf);
+}
+
+static inline ssize_t adt7316_set_in_temp_high(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return adt7316_set_ad_bound(dev, attr,
+                       ADT7316_IN_TEMP_HIGH, buf, len);
+}
+
+static ssize_t adt7316_show_in_temp_low(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return adt7316_show_ad_bound(dev, attr,
+                       ADT7316_IN_TEMP_LOW, buf);
+}
+
+static inline ssize_t adt7316_set_in_temp_low(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return adt7316_set_ad_bound(dev, attr,
+                       ADT7316_IN_TEMP_LOW, buf, len);
+}
+
+static ssize_t adt7316_show_ex_temp_ain1_high(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return adt7316_show_ad_bound(dev, attr,
+                       ADT7316_EX_TEMP_HIGH, buf);
+}
+
+static inline ssize_t adt7316_set_ex_temp_ain1_high(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return adt7316_set_ad_bound(dev, attr,
+                       ADT7316_EX_TEMP_HIGH, buf, len);
+}
+
+static ssize_t adt7316_show_ex_temp_ain1_low(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return adt7316_show_ad_bound(dev, attr,
+                       ADT7316_EX_TEMP_LOW, buf);
+}
+
+static inline ssize_t adt7316_set_ex_temp_ain1_low(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return adt7316_set_ad_bound(dev, attr,
+                       ADT7316_EX_TEMP_LOW, buf, len);
+}
+
+static ssize_t adt7316_show_ain2_high(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return adt7316_show_ad_bound(dev, attr,
+                       ADT7516_AIN2_HIGH, buf);
+}
+
+static inline ssize_t adt7316_set_ain2_high(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return adt7316_set_ad_bound(dev, attr,
+                       ADT7516_AIN2_HIGH, buf, len);
+}
+
+static ssize_t adt7316_show_ain2_low(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return adt7316_show_ad_bound(dev, attr,
+                       ADT7516_AIN2_LOW, buf);
+}
+
+static inline ssize_t adt7316_set_ain2_low(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return adt7316_set_ad_bound(dev, attr,
+                       ADT7516_AIN2_LOW, buf, len);
+}
+
+static ssize_t adt7316_show_ain3_high(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return adt7316_show_ad_bound(dev, attr,
+                       ADT7516_AIN3_HIGH, buf);
+}
+
+static inline ssize_t adt7316_set_ain3_high(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return adt7316_set_ad_bound(dev, attr,
+                       ADT7516_AIN3_HIGH, buf, len);
+}
+
+static ssize_t adt7316_show_ain3_low(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return adt7316_show_ad_bound(dev, attr,
+                       ADT7516_AIN3_LOW, buf);
+}
+
+static inline ssize_t adt7316_set_ain3_low(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return adt7316_set_ad_bound(dev, attr,
+                       ADT7516_AIN3_LOW, buf, len);
+}
+
+static ssize_t adt7316_show_ain4_high(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return adt7316_show_ad_bound(dev, attr,
+                       ADT7516_AIN4_HIGH, buf);
+}
+
+static inline ssize_t adt7316_set_ain4_high(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return adt7316_set_ad_bound(dev, attr,
+                       ADT7516_AIN4_HIGH, buf, len);
+}
+
+static ssize_t adt7316_show_ain4_low(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return adt7316_show_ad_bound(dev, attr,
+                       ADT7516_AIN4_LOW, buf);
+}
+
+static inline ssize_t adt7316_set_ain4_low(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       return adt7316_set_ad_bound(dev, attr,
+                       ADT7516_AIN4_LOW, buf, len);
+}
+
+static ssize_t adt7316_show_int_enabled(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_INT_EN));
+}
+
+static ssize_t adt7316_set_int_enabled(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       u8 config1;
+       int ret;
+
+       config1 = chip->config1 & (~ADT7316_INT_EN);
+       if (!memcmp(buf, "1", 1))
+               config1 |= ADT7316_INT_EN;
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, config1);
+       if (ret)
+               return -EIO;
+
+       chip->config1 = config1;
+
+       return len;
+}
+
+
+IIO_EVENT_ATTR_SH(int_mask, iio_event_adt7316,
+               adt7316_show_int_mask, adt7316_set_int_mask, 0);
+IIO_EVENT_ATTR_SH(in_temp_high, iio_event_adt7316,
+               adt7316_show_in_temp_high, adt7316_set_in_temp_high, 0);
+IIO_EVENT_ATTR_SH(in_temp_low, iio_event_adt7316,
+               adt7316_show_in_temp_low, adt7316_set_in_temp_low, 0);
+IIO_EVENT_ATTR_SH(ex_temp_high, iio_event_adt7316,
+               adt7316_show_ex_temp_ain1_high,
+               adt7316_set_ex_temp_ain1_high, 0);
+IIO_EVENT_ATTR_SH(ex_temp_low, iio_event_adt7316,
+               adt7316_show_ex_temp_ain1_low,
+               adt7316_set_ex_temp_ain1_low, 0);
+IIO_EVENT_ATTR_SH(ex_temp_ain1_high, iio_event_adt7316,
+               adt7316_show_ex_temp_ain1_high,
+               adt7316_set_ex_temp_ain1_high, 0);
+IIO_EVENT_ATTR_SH(ex_temp_ain1_low, iio_event_adt7316,
+               adt7316_show_ex_temp_ain1_low,
+               adt7316_set_ex_temp_ain1_low, 0);
+IIO_EVENT_ATTR_SH(ain2_high, iio_event_adt7316,
+               adt7316_show_ain2_high, adt7316_set_ain2_high, 0);
+IIO_EVENT_ATTR_SH(ain2_low, iio_event_adt7316,
+               adt7316_show_ain2_low, adt7316_set_ain2_low, 0);
+IIO_EVENT_ATTR_SH(ain3_high, iio_event_adt7316,
+               adt7316_show_ain3_high, adt7316_set_ain3_high, 0);
+IIO_EVENT_ATTR_SH(ain3_low, iio_event_adt7316,
+               adt7316_show_ain3_low, adt7316_set_ain3_low, 0);
+IIO_EVENT_ATTR_SH(ain4_high, iio_event_adt7316,
+               adt7316_show_ain4_high, adt7316_set_ain4_high, 0);
+IIO_EVENT_ATTR_SH(ain4_low, iio_event_adt7316,
+               adt7316_show_ain4_low, adt7316_set_ain4_low, 0);
+IIO_EVENT_ATTR_SH(int_enabled, iio_event_adt7316,
+               adt7316_show_int_enabled, adt7316_set_int_enabled, 0);
+
+static struct attribute *adt7316_event_attributes[] = {
+       &iio_event_attr_int_mask.dev_attr.attr,
+       &iio_event_attr_in_temp_high.dev_attr.attr,
+       &iio_event_attr_in_temp_low.dev_attr.attr,
+       &iio_event_attr_ex_temp_high.dev_attr.attr,
+       &iio_event_attr_ex_temp_low.dev_attr.attr,
+       &iio_event_attr_int_enabled.dev_attr.attr,
+       NULL,
+};
+
+static struct attribute_group adt7316_event_attribute_group = {
+       .attrs = adt7316_event_attributes,
+};
+
+static struct attribute *adt7516_event_attributes[] = {
+       &iio_event_attr_int_mask.dev_attr.attr,
+       &iio_event_attr_in_temp_high.dev_attr.attr,
+       &iio_event_attr_in_temp_low.dev_attr.attr,
+       &iio_event_attr_ex_temp_ain1_high.dev_attr.attr,
+       &iio_event_attr_ex_temp_ain1_low.dev_attr.attr,
+       &iio_event_attr_ain2_high.dev_attr.attr,
+       &iio_event_attr_ain2_low.dev_attr.attr,
+       &iio_event_attr_ain3_high.dev_attr.attr,
+       &iio_event_attr_ain3_low.dev_attr.attr,
+       &iio_event_attr_ain4_high.dev_attr.attr,
+       &iio_event_attr_ain4_low.dev_attr.attr,
+       &iio_event_attr_int_enabled.dev_attr.attr,
+       NULL,
+};
+
+static struct attribute_group adt7516_event_attribute_group = {
+       .attrs = adt7516_event_attributes,
+};
+
+#ifdef CONFIG_PM
+int adt7316_disable(struct device *dev)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return _adt7316_store_enabled(chip, 0);
+}
+EXPORT_SYMBOL(adt7316_disable);
+
+int adt7316_enable(struct device *dev)
+{
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+
+       return _adt7316_store_enabled(chip, 1);
+}
+EXPORT_SYMBOL(adt7316_enable);
+#endif
+
+/*
+ * device probe and remove
+ */
+int __devinit adt7316_probe(struct device *dev, struct adt7316_bus *bus,
+               const char *name)
+{
+       struct adt7316_chip_info *chip;
+       unsigned short *adt7316_platform_data = dev->platform_data;
+       int ret = 0;
+
+       chip = kzalloc(sizeof(struct adt7316_chip_info), GFP_KERNEL);
+
+       if (chip == NULL)
+               return -ENOMEM;
+
+       /* this is only used for device removal purposes */
+       dev_set_drvdata(dev, chip);
+
+       chip->bus = *bus;
+       chip->name = name;
+
+       if (name[4] == '3')
+               chip->id = ID_ADT7316 + (name[6] - '6');
+       else if (name[4] == '5')
+               chip->id = ID_ADT7516 + (name[6] - '6');
+       else
+               return -ENODEV;
+
+       chip->ldac_pin = adt7316_platform_data[1];
+       if (chip->ldac_pin) {
+               chip->config3 |= ADT7316_DA_EN_VIA_DAC_LDCA;
+               if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+                       chip->config1 |= ADT7516_SEL_AIN3;
+       }
+       chip->int_mask = ADT7316_TEMP_INT_MASK | ADT7316_VDD_INT_MASK;
+       if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
+               chip->int_mask |= ADT7516_AIN_INT_MASK;
+
+       chip->indio_dev = iio_allocate_device();
+       if (chip->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_chip;
+       }
+
+       chip->indio_dev->dev.parent = dev;
+       if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) {
+               chip->indio_dev->attrs = &adt7516_attribute_group;
+               chip->indio_dev->event_attrs = &adt7516_event_attribute_group;
+       } else {
+               chip->indio_dev->attrs = &adt7316_attribute_group;
+               chip->indio_dev->event_attrs = &adt7316_event_attribute_group;
+       }
+       chip->indio_dev->dev_data = (void *)chip;
+       chip->indio_dev->driver_module = THIS_MODULE;
+       chip->indio_dev->num_interrupt_lines = 1;
+       chip->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(chip->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       if (chip->bus.irq > 0) {
+               if (adt7316_platform_data[0])
+                       chip->bus.irq_flags = adt7316_platform_data[0];
+
+               ret = iio_register_interrupt_line(chip->bus.irq,
+                               chip->indio_dev,
+                               0,
+                               chip->bus.irq_flags,
+                               chip->name);
+               if (ret)
+                       goto error_unreg_dev;
+
+               /*
+                * The event handler list element refer to iio_event_adt7316.
+                * All event attributes bind to the same event handler.
+                * So, only register event handler once.
+                */
+               iio_add_event_to_list(&iio_event_adt7316,
+                               &chip->indio_dev->interrupts[0]->ev_list);
+
+               INIT_WORK(&chip->thresh_work, adt7316_interrupt_bh);
+
+               if (chip->bus.irq_flags & IRQF_TRIGGER_HIGH)
+                       chip->config1 |= ADT7316_INT_POLARITY;
+       }
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG1, chip->config1);
+       if (ret) {
+               ret = -EIO;
+               goto error_unreg_irq;
+       }
+
+       ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, chip->config3);
+       if (ret) {
+               ret = -EIO;
+               goto error_unreg_irq;
+       }
+
+       dev_info(dev, "%s temperature sensor, ADC and DAC registered.\n",
+                       chip->name);
+
+       return 0;
+
+error_unreg_irq:
+       iio_unregister_interrupt_line(chip->indio_dev, 0);
+error_unreg_dev:
+       iio_device_unregister(chip->indio_dev);
+error_free_dev:
+       iio_free_device(chip->indio_dev);
+error_free_chip:
+       kfree(chip);
+
+       return ret;
+}
+EXPORT_SYMBOL(adt7316_probe);
+
+int __devexit adt7316_remove(struct device *dev)
+{
+
+       struct iio_dev *dev_info = dev_get_drvdata(dev);
+       struct adt7316_chip_info *chip = dev_info->dev_data;
+       struct iio_dev *indio_dev = chip->indio_dev;
+
+       dev_set_drvdata(dev, NULL);
+       if (chip->bus.irq)
+               iio_unregister_interrupt_line(indio_dev, 0);
+       iio_device_unregister(indio_dev);
+       iio_free_device(chip->indio_dev);
+       kfree(chip);
+
+       return 0;
+}
+EXPORT_SYMBOL(adt7316_remove);
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("Analog Devices ADT7316/7/8 and ADT7516/7/9 digital"
+                       " temperature sensor, ADC and DAC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/addac/adt7316.h b/drivers/staging/iio/addac/adt7316.h
new file mode 100644 (file)
index 0000000..d34bd67
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * ADT7316 digital temperature sensor driver supporting ADT7316/7/8 ADT7516/7/9
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _ADT7316_H_
+#define _ADT7316_H_
+
+#include <linux/types.h>
+
+#define ADT7316_REG_MAX_ADDR           0x3F
+
+struct adt7316_bus {
+       void *client;
+       int irq;
+       int irq_flags;
+       int (*read) (void *client, u8 reg, u8 *data);
+       int (*write) (void *client, u8 reg, u8 val);
+       int (*multi_read) (void *client, u8 first_reg, u8 count, u8 *data);
+       int (*multi_write) (void *client, u8 first_reg, u8 count, u8 *data);
+};
+
+#ifdef CONFIG_PM
+int adt7316_disable(struct device *dev);
+int adt7316_enable(struct device *dev);
+#endif
+int adt7316_probe(struct device *dev, struct adt7316_bus *bus, const char *name);
+int adt7316_remove(struct device *dev);
+
+#endif
diff --git a/drivers/staging/iio/dac/Kconfig b/drivers/staging/iio/dac/Kconfig
new file mode 100644 (file)
index 0000000..583df78
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# DAC drivers
+#
+comment "Digital to analog convertors"
+
+config AD5624R_SPI
+       tristate "Analog Devices AD5624/44/64R DAC spi driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices AD5624R, AD5644R and
+         AD5664R convertors (DAC). This driver uses the common SPI interface.
diff --git a/drivers/staging/iio/dac/Makefile b/drivers/staging/iio/dac/Makefile
new file mode 100644 (file)
index 0000000..7ddf05d
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for industrial I/O DAC drivers
+#
+
+obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o
diff --git a/drivers/staging/iio/dac/ad5624r.h b/drivers/staging/iio/dac/ad5624r.h
new file mode 100644 (file)
index 0000000..ce518be
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef SPI_AD5624R_H_
+#define SPI_AD5624R_H_
+
+#define AD5624R_DAC_CHANNELS   4
+
+#define AD5624R_ADDR_DAC0      0x0
+#define AD5624R_ADDR_DAC1      0x1
+#define AD5624R_ADDR_DAC2      0x2
+#define AD5624R_ADDR_DAC3      0x3
+#define AD5624R_ADDR_ALL_DAC   0x7
+
+#define AD5624R_CMD_WRITE_INPUT_N             0x0
+#define AD5624R_CMD_UPDATE_DAC_N              0x1
+#define AD5624R_CMD_WRITE_INPUT_N_UPDATE_ALL  0x2
+#define AD5624R_CMD_WRITE_INPUT_N_UPDATE_N    0x3
+#define AD5624R_CMD_POWERDOWN_DAC             0x4
+#define AD5624R_CMD_RESET                     0x5
+#define AD5624R_CMD_LDAC_SETUP                0x6
+#define AD5624R_CMD_INTERNAL_REFER_SETUP      0x7
+
+#endif
diff --git a/drivers/staging/iio/dac/ad5624r_spi.c b/drivers/staging/iio/dac/ad5624r_spi.c
new file mode 100644 (file)
index 0000000..705ff50
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * AD5624R, AD5644R, AD5664R Digital to analog convertors spi driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/delay.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "dac.h"
+#include "ad5624r.h"
+
+/**
+ * struct ad5624r_state - device related storage
+ * @indio_dev: associated industrial IO device
+ * @us:                spi device
+ **/
+struct ad5624r_state {
+       struct iio_dev *indio_dev;
+       struct spi_device *us;
+       int data_len;
+       int ldac_mode;
+       int dac_power_mode[AD5624R_DAC_CHANNELS];
+       int internal_ref;
+};
+
+static int ad5624r_spi_write(struct spi_device *spi, u8 cmd, u8 addr, u16 val, u8 len)
+{
+       struct spi_transfer t;
+       struct spi_message m;
+       u32 data;
+       u8 msg[3];
+
+       /*
+        * The input shift register is 24 bits wide. The first two bits are don't care bits.
+        * The next three are the command bits, C2 to C0, followed by the 3-bit DAC address,
+        * A2 to A0, and then the 16-, 14-, 12-bit data-word. The data-word comprises the 16-,
+        * 14-, 12-bit input code followed by 0, 2, or 4 don't care bits, for the AD5664R,
+        * AD5644R, and AD5624R, respectively.
+        */
+       data = (0 << 22) | (cmd << 19) | (addr << 16) | (val << (16 - len));
+       msg[0] = data >> 16;
+       msg[1] = data >> 8;
+       msg[2] = data;
+
+       spi_message_init(&m);
+       memset(&t, 0, (sizeof t));
+       t.tx_buf = &msg[0];
+       t.len = 3;
+
+       spi_message_add_tail(&t, &m);
+       spi_sync(spi, &m);
+
+       return len;
+}
+
+static ssize_t ad5624r_write_dac(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       long readin;
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ad5624r_state *st = indio_dev->dev_data;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = strict_strtol(buf, 10, &readin);
+       if (ret)
+               return ret;
+
+       ad5624r_spi_write(st->us, AD5624R_CMD_WRITE_INPUT_N_UPDATE_N,
+                       this_attr->address, readin, st->data_len);
+       return ret ? ret : len;
+}
+
+static ssize_t ad5624r_read_ldac_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ad5624r_state *st = indio_dev->dev_data;
+
+       return sprintf(buf, "%x\n", st->ldac_mode);
+}
+
+static ssize_t ad5624r_write_ldac_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       long readin;
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ad5624r_state *st = indio_dev->dev_data;
+
+       ret = strict_strtol(buf, 16, &readin);
+       if (ret)
+               return ret;
+
+       ad5624r_spi_write(st->us, AD5624R_CMD_LDAC_SETUP, 0, readin & 0xF, 16);
+       st->ldac_mode = readin & 0xF;
+
+       return ret ? ret : len;
+}
+
+static ssize_t ad5624r_read_dac_power_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ad5624r_state *st = indio_dev->dev_data;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       return sprintf(buf, "%d\n", st->dac_power_mode[this_attr->address]);
+}
+
+static ssize_t ad5624r_write_dac_power_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       long readin;
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ad5624r_state *st = indio_dev->dev_data;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = strict_strtol(buf, 10, &readin);
+       if (ret)
+               return ret;
+
+       ad5624r_spi_write(st->us, AD5624R_CMD_POWERDOWN_DAC, 0,
+                       ((readin & 0x3) << 4) | (1 << this_attr->address), 16);
+
+       st->dac_power_mode[this_attr->address] = readin & 0x3;
+
+       return ret ? ret : len;
+}
+
+static ssize_t ad5624r_read_internal_ref_mode(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ad5624r_state *st = indio_dev->dev_data;
+
+       return sprintf(buf, "%d\n", st->internal_ref);
+}
+
+static ssize_t ad5624r_write_internal_ref_mode(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       long readin;
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ad5624r_state *st = indio_dev->dev_data;
+
+       ret = strict_strtol(buf, 10, &readin);
+       if (ret)
+               return ret;
+
+       ad5624r_spi_write(st->us, AD5624R_CMD_INTERNAL_REFER_SETUP, 0, !!readin, 16);
+
+       st->internal_ref = !!readin;
+
+       return ret ? ret : len;
+}
+
+static IIO_DEV_ATTR_DAC(0, ad5624r_write_dac, AD5624R_ADDR_DAC0);
+static IIO_DEV_ATTR_DAC(1, ad5624r_write_dac, AD5624R_ADDR_DAC1);
+static IIO_DEV_ATTR_DAC(2, ad5624r_write_dac, AD5624R_ADDR_DAC2);
+static IIO_DEV_ATTR_DAC(3, ad5624r_write_dac, AD5624R_ADDR_DAC3);
+
+static IIO_DEVICE_ATTR(ldac_mode, S_IRUGO | S_IWUSR, ad5624r_read_ldac_mode,
+               ad5624r_write_ldac_mode, 0);
+static IIO_DEVICE_ATTR(internal_ref, S_IRUGO | S_IWUSR, ad5624r_read_internal_ref_mode,
+               ad5624r_write_internal_ref_mode, 0);
+
+#define IIO_DEV_ATTR_DAC_POWER_MODE(_num, _show, _store, _addr)                        \
+       IIO_DEVICE_ATTR(dac_power_mode_##_num, S_IRUGO | S_IWUSR, _show, _store, _addr)
+
+static IIO_DEV_ATTR_DAC_POWER_MODE(0, ad5624r_read_dac_power_mode, ad5624r_write_dac_power_mode, 0);
+static IIO_DEV_ATTR_DAC_POWER_MODE(1, ad5624r_read_dac_power_mode, ad5624r_write_dac_power_mode, 1);
+static IIO_DEV_ATTR_DAC_POWER_MODE(2, ad5624r_read_dac_power_mode, ad5624r_write_dac_power_mode, 2);
+static IIO_DEV_ATTR_DAC_POWER_MODE(3, ad5624r_read_dac_power_mode, ad5624r_write_dac_power_mode, 3);
+
+static struct attribute *ad5624r_attributes[] = {
+       &iio_dev_attr_dac_0.dev_attr.attr,
+       &iio_dev_attr_dac_1.dev_attr.attr,
+       &iio_dev_attr_dac_2.dev_attr.attr,
+       &iio_dev_attr_dac_3.dev_attr.attr,
+       &iio_dev_attr_dac_power_mode_0.dev_attr.attr,
+       &iio_dev_attr_dac_power_mode_1.dev_attr.attr,
+       &iio_dev_attr_dac_power_mode_2.dev_attr.attr,
+       &iio_dev_attr_dac_power_mode_3.dev_attr.attr,
+       &iio_dev_attr_ldac_mode.dev_attr.attr,
+       &iio_dev_attr_internal_ref.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ad5624r_attribute_group = {
+       .attrs = ad5624r_attributes,
+};
+
+static int __devinit ad5624r_probe(struct spi_device *spi)
+{
+
+       struct ad5624r_state *st;
+       int ret = 0;
+       char *chip_name = spi->dev.platform_data;
+
+       if (!chip_name)
+               return -ENODEV;
+
+       st = kzalloc(sizeof(*st), GFP_KERNEL);
+       if (st == NULL) {
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+       spi_set_drvdata(spi, st);
+
+       if (strcmp(chip_name, "ad5624r") == 0)
+               st->data_len = 12;
+       else if (strcmp(chip_name, "ad5644r") == 0)
+               st->data_len = 14;
+       else if (strcmp(chip_name, "ad5664r") == 0)
+               st->data_len = 16;
+       else {
+               dev_err(&spi->dev, "not supported chip type\n");
+               ret = -EINVAL;
+               goto error_ret;
+       }
+
+       st->us = spi;
+       st->indio_dev = iio_allocate_device();
+       if (st->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->indio_dev->dev.parent = &spi->dev;
+       st->indio_dev->num_interrupt_lines = 0;
+       st->indio_dev->event_attrs = NULL;
+
+       st->indio_dev->attrs = &ad5624r_attribute_group;
+       st->indio_dev->dev_data = (void *)(st);
+       st->indio_dev->driver_module = THIS_MODULE;
+       st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(st->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       spi->mode = SPI_MODE_0;
+       spi_setup(spi);
+
+       return 0;
+
+error_free_dev:
+       iio_free_device(st->indio_dev);
+error_free_st:
+       kfree(st);
+error_ret:
+       return ret;
+}
+
+static int __devexit ad5624r_remove(struct spi_device *spi)
+{
+       struct ad5624r_state *st = spi_get_drvdata(spi);
+
+       iio_device_unregister(st->indio_dev);
+       kfree(st);
+
+       return 0;
+}
+
+static struct spi_driver ad5624r_driver = {
+       .driver = {
+               .name = "ad5624r",
+               .owner = THIS_MODULE,
+       },
+       .probe = ad5624r_probe,
+       .remove = __devexit_p(ad5624r_remove),
+};
+
+static __init int ad5624r_spi_init(void)
+{
+       return spi_register_driver(&ad5624r_driver);
+}
+module_init(ad5624r_spi_init);
+
+static __exit void ad5624r_spi_exit(void)
+{
+       spi_unregister_driver(&ad5624r_driver);
+}
+module_exit(ad5624r_spi_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices AD5624/44/64R DAC spi driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dac/dac.h b/drivers/staging/iio/dac/dac.h
new file mode 100644 (file)
index 0000000..55005ee
--- /dev/null
@@ -0,0 +1,6 @@
+/*
+ * dac.h - sysfs attributes associated with DACs
+ */
+
+#define IIO_DEV_ATTR_DAC(_num, _store, _addr)                  \
+       IIO_DEVICE_ATTR(dac_##_num, S_IWUSR, NULL, _store, _addr)
diff --git a/drivers/staging/iio/dds/Kconfig b/drivers/staging/iio/dds/Kconfig
new file mode 100644 (file)
index 0000000..d045ed6
--- /dev/null
@@ -0,0 +1,46 @@
+#
+# Direct Digital Synthesis drivers
+#
+comment "Direct Digital Synthesis"
+
+config AD5930
+       tristate "Analog Devices ad5930/5932 driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices DDS chip
+         ad5930/ad5932, provides direct access via sysfs.
+
+config AD9832
+       tristate "Analog Devices ad9832/3/4/5 driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices DDS chip
+         ad9832/3/4/5, provides direct access via sysfs.
+
+config AD9850
+       tristate "Analog Devices ad9850/1 driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices DDS chip
+         ad9850/1, provides direct access via sysfs.
+
+config AD9852
+       tristate "Analog Devices ad9852/4 driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices DDS chip
+         ad9852/4, provides direct access via sysfs.
+
+config AD9910
+       tristate "Analog Devices ad9910 driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices DDS chip
+         ad9910, provides direct access via sysfs.
+
+config AD9951
+       tristate "Analog Devices ad9951 driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices DDS chip
+         ad9951, provides direct access via sysfs.
diff --git a/drivers/staging/iio/dds/Makefile b/drivers/staging/iio/dds/Makefile
new file mode 100644 (file)
index 0000000..6f274ac
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Makefile for Direct Digital Synthesis drivers
+#
+
+obj-$(CONFIG_AD5930) += ad5930.o
+obj-$(CONFIG_AD9832) += ad9832.o
+obj-$(CONFIG_AD9850) += ad9850.o
+obj-$(CONFIG_AD9852) += ad9852.o
+obj-$(CONFIG_AD9910) += ad9910.o
+obj-$(CONFIG_AD9951) += ad9951.o
diff --git a/drivers/staging/iio/dds/ad5930.c b/drivers/staging/iio/dds/ad5930.c
new file mode 100644 (file)
index 0000000..f80039c
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad5930
+ *
+ * Copyright (c) 2010-2010 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad5930"
+
+#define value_mask (u16)0xf000
+#define addr_shift 12
+
+/* Register format: 4 bits addr + 12 bits value */
+struct ad5903_config {
+       u16 control;
+       u16 incnum;
+       u16 frqdelt[2];
+       u16 incitvl;
+       u16 buritvl;
+       u16 strtfrq[2];
+};
+
+struct ad5930_state {
+       struct mutex lock;
+       struct iio_dev *idev;
+       struct spi_device *sdev;
+};
+
+static ssize_t ad5930_set_parameter(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf,
+                                       size_t len)
+{
+       struct spi_message msg;
+       struct spi_transfer xfer;
+       int ret;
+       struct ad5903_config *config = (struct ad5903_config *)buf;
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad5930_state *st = idev->dev_data;
+
+       config->control = (config->control & ~value_mask);
+       config->incnum = (config->control & ~value_mask) | (1 << addr_shift);
+       config->frqdelt[0] = (config->control & ~value_mask) | (2 << addr_shift);
+       config->frqdelt[1] = (config->control & ~value_mask) | 3 << addr_shift;
+       config->incitvl = (config->control & ~value_mask) | 4 << addr_shift;
+       config->buritvl = (config->control & ~value_mask) | 8 << addr_shift;
+       config->strtfrq[0] = (config->control & ~value_mask) | 0xc << addr_shift;
+       config->strtfrq[1] = (config->control & ~value_mask) | 0xd << addr_shift;
+
+       xfer.len = len;
+       xfer.tx_buf = config;
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+error_ret:
+       mutex_unlock(&st->lock);
+
+       return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad5930_set_parameter, 0);
+
+static struct attribute *ad5930_attributes[] = {
+       &iio_dev_attr_dds.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ad5930_attribute_group = {
+       .name = DRV_NAME,
+       .attrs = ad5930_attributes,
+};
+
+static int __devinit ad5930_probe(struct spi_device *spi)
+{
+       struct ad5930_state *st;
+       int ret = 0;
+
+       st = kzalloc(sizeof(*st), GFP_KERNEL);
+       if (st == NULL) {
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+       spi_set_drvdata(spi, st);
+
+       mutex_init(&st->lock);
+       st->sdev = spi;
+
+       st->idev = iio_allocate_device();
+       if (st->idev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->idev->dev.parent = &spi->dev;
+       st->idev->num_interrupt_lines = 0;
+       st->idev->event_attrs = NULL;
+
+       st->idev->attrs = &ad5930_attribute_group;
+       st->idev->dev_data = (void *)(st);
+       st->idev->driver_module = THIS_MODULE;
+       st->idev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(st->idev);
+       if (ret)
+               goto error_free_dev;
+       spi->max_speed_hz = 2000000;
+       spi->mode = SPI_MODE_3;
+       spi->bits_per_word = 16;
+       spi_setup(spi);
+
+       return 0;
+
+error_free_dev:
+       iio_free_device(st->idev);
+error_free_st:
+       kfree(st);
+error_ret:
+       return ret;
+}
+
+static int __devexit ad5930_remove(struct spi_device *spi)
+{
+       struct ad5930_state *st = spi_get_drvdata(spi);
+
+       iio_device_unregister(st->idev);
+       kfree(st);
+
+       return 0;
+}
+
+static struct spi_driver ad5930_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = ad5930_probe,
+       .remove = __devexit_p(ad5930_remove),
+};
+
+static __init int ad5930_spi_init(void)
+{
+       return spi_register_driver(&ad5930_driver);
+}
+module_init(ad5930_spi_init);
+
+static __exit void ad5930_spi_exit(void)
+{
+       spi_unregister_driver(&ad5930_driver);
+}
+module_exit(ad5930_spi_exit);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad5930 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/ad9832.c b/drivers/staging/iio/dds/ad9832.c
new file mode 100644 (file)
index 0000000..a4bb048
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad9832
+ *
+ * Copyright (c) 2010 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad9832"
+
+#define value_mask (u16)0xf000
+#define cmd_shift 12
+#define add_shift 8
+#define AD9832_SYNC (1 << 13)
+#define AD9832_SELSRC (1 << 12)
+#define AD9832_SLEEP (1 << 13)
+#define AD9832_RESET (1 << 12)
+#define AD9832_CLR (1 << 11)
+
+#define ADD_FREQ0LL 0x0
+#define ADD_FREQ0HL 0x1
+#define ADD_FREQ0LM 0x2
+#define ADD_FREQ0HM 0x3
+#define ADD_FREQ1LL 0x4
+#define ADD_FREQ1HL 0x5
+#define ADD_FREQ1LM 0x6
+#define ADD_FREQ1HM 0x7
+#define ADD_PHASE0L 0x8
+#define ADD_PHASE0H 0x9
+#define ADD_PHASE1L 0xa
+#define ADD_PHASE1H 0xb
+#define ADD_PHASE2L 0xc
+#define ADD_PHASE2H 0xd
+#define ADD_PHASE3L 0xe
+#define ADD_PHASE3H 0xf
+
+#define CMD_PHA8BITSW 0x1
+#define CMD_PHA16BITSW 0x0
+#define CMD_FRE8BITSW 0x3
+#define CMD_FRE16BITSW 0x2
+#define CMD_SELBITSCTL 0x6
+
+struct ad9832_setting {
+       u16 freq0[4];
+       u16 freq1[4];
+       u16 phase0[2];
+       u16 phase1[2];
+       u16 phase2[2];
+       u16 phase3[2];
+};
+
+struct ad9832_state {
+       struct mutex lock;
+       struct iio_dev *idev;
+       struct spi_device *sdev;
+};
+
+static ssize_t ad9832_set_parameter(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf,
+                                       size_t len)
+{
+       struct spi_message msg;
+       struct spi_transfer xfer;
+       int ret;
+       struct ad9832_setting config;
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad9832_state *st = idev->dev_data;
+
+       config.freq0[0] = (CMD_FRE8BITSW << add_shift | ADD_FREQ0LL << add_shift | buf[0]);
+       config.freq0[1] = (CMD_FRE16BITSW << add_shift | ADD_FREQ0HL << add_shift | buf[1]);
+       config.freq0[2] = (CMD_FRE8BITSW << add_shift | ADD_FREQ0LM << add_shift | buf[2]);
+       config.freq0[3] = (CMD_FRE16BITSW << add_shift | ADD_FREQ0HM << add_shift | buf[3]);
+       config.freq1[0] = (CMD_FRE8BITSW << add_shift | ADD_FREQ1LL << add_shift | buf[4]);
+       config.freq1[1] = (CMD_FRE16BITSW << add_shift | ADD_FREQ1HL << add_shift | buf[5]);
+       config.freq1[2] = (CMD_FRE8BITSW << add_shift | ADD_FREQ1LM << add_shift | buf[6]);
+       config.freq1[3] = (CMD_FRE16BITSW << add_shift | ADD_FREQ1HM << add_shift | buf[7]);
+
+       config.phase0[0] = (CMD_PHA8BITSW << add_shift | ADD_PHASE0L << add_shift | buf[9]);
+       config.phase0[1] = (CMD_PHA16BITSW << add_shift | ADD_PHASE0H << add_shift | buf[10]);
+       config.phase1[0] = (CMD_PHA8BITSW << add_shift | ADD_PHASE1L << add_shift | buf[11]);
+       config.phase1[1] = (CMD_PHA16BITSW << add_shift | ADD_PHASE1H << add_shift | buf[12]);
+       config.phase2[0] = (CMD_PHA8BITSW << add_shift | ADD_PHASE2L << add_shift | buf[13]);
+       config.phase2[1] = (CMD_PHA16BITSW << add_shift | ADD_PHASE2H << add_shift | buf[14]);
+       config.phase3[0] = (CMD_PHA8BITSW << add_shift | ADD_PHASE3L << add_shift | buf[15]);
+       config.phase3[1] = (CMD_PHA16BITSW << add_shift | ADD_PHASE3H << add_shift | buf[16]);
+
+       xfer.len = 2 * len;
+       xfer.tx_buf = &config;
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+error_ret:
+       mutex_unlock(&st->lock);
+
+       return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9832_set_parameter, 0);
+
+static struct attribute *ad9832_attributes[] = {
+       &iio_dev_attr_dds.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ad9832_attribute_group = {
+       .name = DRV_NAME,
+       .attrs = ad9832_attributes,
+};
+
+static void ad9832_init(struct ad9832_state *st)
+{
+       struct spi_message msg;
+       struct spi_transfer xfer;
+       int ret;
+       u16 config = 0;
+
+       config = 0x3 << 14 | AD9832_SLEEP | AD9832_RESET | AD9832_CLR;
+
+       mutex_lock(&st->lock);
+
+       xfer.len = 2;
+       xfer.tx_buf = &config;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       config = 0x2 << 14 | AD9832_SYNC | AD9832_SELSRC;
+       xfer.len = 2;
+       xfer.tx_buf = &config;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       config = CMD_SELBITSCTL << cmd_shift;
+       xfer.len = 2;
+       xfer.tx_buf = &config;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       config = 0x3 << 14;
+
+       mutex_lock(&st->lock);
+
+       xfer.len = 2;
+       xfer.tx_buf = &config;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+error_ret:
+       mutex_unlock(&st->lock);
+
+
+
+}
+
+static int __devinit ad9832_probe(struct spi_device *spi)
+{
+       struct ad9832_state *st;
+       int ret = 0;
+
+       st = kzalloc(sizeof(*st), GFP_KERNEL);
+       if (st == NULL) {
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+       spi_set_drvdata(spi, st);
+
+       mutex_init(&st->lock);
+       st->sdev = spi;
+
+       st->idev = iio_allocate_device();
+       if (st->idev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->idev->dev.parent = &spi->dev;
+       st->idev->num_interrupt_lines = 0;
+       st->idev->event_attrs = NULL;
+
+       st->idev->attrs = &ad9832_attribute_group;
+       st->idev->dev_data = (void *)(st);
+       st->idev->driver_module = THIS_MODULE;
+       st->idev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(st->idev);
+       if (ret)
+               goto error_free_dev;
+       spi->max_speed_hz = 2000000;
+       spi->mode = SPI_MODE_3;
+       spi->bits_per_word = 16;
+       spi_setup(spi);
+       ad9832_init(st);
+       return 0;
+
+error_free_dev:
+       iio_free_device(st->idev);
+error_free_st:
+       kfree(st);
+error_ret:
+       return ret;
+}
+
+static int __devexit ad9832_remove(struct spi_device *spi)
+{
+       struct ad9832_state *st = spi_get_drvdata(spi);
+
+       iio_device_unregister(st->idev);
+       kfree(st);
+
+       return 0;
+}
+
+static struct spi_driver ad9832_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = ad9832_probe,
+       .remove = __devexit_p(ad9832_remove),
+};
+
+static __init int ad9832_spi_init(void)
+{
+       return spi_register_driver(&ad9832_driver);
+}
+module_init(ad9832_spi_init);
+
+static __exit void ad9832_spi_exit(void)
+{
+       spi_unregister_driver(&ad9832_driver);
+}
+module_exit(ad9832_spi_exit);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad9832 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/ad9850.c b/drivers/staging/iio/dds/ad9850.c
new file mode 100644 (file)
index 0000000..b259bfe
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad9850
+ *
+ * Copyright (c) 2010-2010 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad9850"
+
+#define value_mask (u16)0xf000
+#define addr_shift 12
+
+/* Register format: 4 bits addr + 12 bits value */
+struct ad9850_config {
+       u8 control[5];
+};
+
+struct ad9850_state {
+       struct mutex lock;
+       struct iio_dev *idev;
+       struct spi_device *sdev;
+};
+
+static ssize_t ad9850_set_parameter(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf,
+                                       size_t len)
+{
+       struct spi_message msg;
+       struct spi_transfer xfer;
+       int ret;
+       struct ad9850_config *config = (struct ad9850_config *)buf;
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad9850_state *st = idev->dev_data;
+
+       xfer.len = len;
+       xfer.tx_buf = config;
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+error_ret:
+       mutex_unlock(&st->lock);
+
+       return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9850_set_parameter, 0);
+
+static struct attribute *ad9850_attributes[] = {
+       &iio_dev_attr_dds.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ad9850_attribute_group = {
+       .name = DRV_NAME,
+       .attrs = ad9850_attributes,
+};
+
+static int __devinit ad9850_probe(struct spi_device *spi)
+{
+       struct ad9850_state *st;
+       int ret = 0;
+
+       st = kzalloc(sizeof(*st), GFP_KERNEL);
+       if (st == NULL) {
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+       spi_set_drvdata(spi, st);
+
+       mutex_init(&st->lock);
+       st->sdev = spi;
+
+       st->idev = iio_allocate_device();
+       if (st->idev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->idev->dev.parent = &spi->dev;
+       st->idev->num_interrupt_lines = 0;
+       st->idev->event_attrs = NULL;
+
+       st->idev->attrs = &ad9850_attribute_group;
+       st->idev->dev_data = (void *)(st);
+       st->idev->driver_module = THIS_MODULE;
+       st->idev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(st->idev);
+       if (ret)
+               goto error_free_dev;
+       spi->max_speed_hz = 2000000;
+       spi->mode = SPI_MODE_3;
+       spi->bits_per_word = 16;
+       spi_setup(spi);
+
+       return 0;
+
+error_free_dev:
+       iio_free_device(st->idev);
+error_free_st:
+       kfree(st);
+error_ret:
+       return ret;
+}
+
+static int __devexit ad9850_remove(struct spi_device *spi)
+{
+       struct ad9850_state *st = spi_get_drvdata(spi);
+
+       iio_device_unregister(st->idev);
+       kfree(st);
+
+       return 0;
+}
+
+static struct spi_driver ad9850_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = ad9850_probe,
+       .remove = __devexit_p(ad9850_remove),
+};
+
+static __init int ad9850_spi_init(void)
+{
+       return spi_register_driver(&ad9850_driver);
+}
+module_init(ad9850_spi_init);
+
+static __exit void ad9850_spi_exit(void)
+{
+       spi_unregister_driver(&ad9850_driver);
+}
+module_exit(ad9850_spi_exit);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad9850 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/ad9852.c b/drivers/staging/iio/dds/ad9852.c
new file mode 100644 (file)
index 0000000..0a41d25
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad9852
+ *
+ * Copyright (c) 2010 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad9852"
+
+#define addr_phaad1 0x0
+#define addr_phaad2 0x1
+#define addr_fretu1 0x2
+#define addr_fretu2 0x3
+#define addr_delfre 0x4
+#define addr_updclk 0x5
+#define addr_ramclk 0x6
+#define addr_contrl 0x7
+#define addr_optskm 0x8
+#define addr_optskr 0xa
+#define addr_dacctl 0xb
+
+#define COMPPD         (1 << 4)
+#define REFMULT2       (1 << 2)
+#define BYPPLL         (1 << 5)
+#define PLLRANG                (1 << 6)
+#define IEUPCLK                (1)
+#define OSKEN          (1 << 5)
+
+#define read_bit       (1 << 7)
+
+/* Register format: 1 byte addr + value */
+struct ad9852_config {
+       u8 phajst0[3];
+       u8 phajst1[3];
+       u8 fretun1[6];
+       u8 fretun2[6];
+       u8 dltafre[6];
+       u8 updtclk[5];
+       u8 ramprat[4];
+       u8 control[5];
+       u8 outpskm[3];
+       u8 outpskr[2];
+       u8 daccntl[3];
+};
+
+struct ad9852_state {
+       struct mutex lock;
+       struct iio_dev *idev;
+       struct spi_device *sdev;
+};
+
+static ssize_t ad9852_set_parameter(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf,
+                                       size_t len)
+{
+       struct spi_message msg;
+       struct spi_transfer xfer;
+       int ret;
+       struct ad9852_config *config = (struct ad9852_config *)buf;
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad9852_state *st = idev->dev_data;
+
+       xfer.len = 3;
+       xfer.tx_buf = &config->phajst0[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 3;
+       xfer.tx_buf = &config->phajst1[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 6;
+       xfer.tx_buf = &config->fretun1[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 6;
+       xfer.tx_buf = &config->fretun2[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 6;
+       xfer.tx_buf = &config->dltafre[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 5;
+       xfer.tx_buf = &config->updtclk[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 4;
+       xfer.tx_buf = &config->ramprat[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 5;
+       xfer.tx_buf = &config->control[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 3;
+       xfer.tx_buf = &config->outpskm[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 2;
+       xfer.tx_buf = &config->outpskr[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+       xfer.len = 3;
+       xfer.tx_buf = &config->daccntl[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+error_ret:
+       mutex_unlock(&st->lock);
+
+       return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9852_set_parameter, 0);
+
+static void ad9852_init(struct ad9852_state *st)
+{
+       struct spi_message msg;
+       struct spi_transfer xfer;
+       int ret;
+       u8 config[5];
+
+       config[0] = addr_contrl;
+       config[1] = COMPPD;
+       config[2] = REFMULT2 | BYPPLL | PLLRANG;
+       config[3] = IEUPCLK;
+       config[4] = OSKEN;
+
+       mutex_lock(&st->lock);
+
+       xfer.len = 5;
+       xfer.tx_buf = &config;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+error_ret:
+       mutex_unlock(&st->lock);
+
+
+
+}
+
+static struct attribute *ad9852_attributes[] = {
+       &iio_dev_attr_dds.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ad9852_attribute_group = {
+       .name = DRV_NAME,
+       .attrs = ad9852_attributes,
+};
+
+static int __devinit ad9852_probe(struct spi_device *spi)
+{
+       struct ad9852_state *st;
+       int ret = 0;
+
+       st = kzalloc(sizeof(*st), GFP_KERNEL);
+       if (st == NULL) {
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+       spi_set_drvdata(spi, st);
+
+       mutex_init(&st->lock);
+       st->sdev = spi;
+
+       st->idev = iio_allocate_device();
+       if (st->idev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->idev->dev.parent = &spi->dev;
+       st->idev->num_interrupt_lines = 0;
+       st->idev->event_attrs = NULL;
+
+       st->idev->attrs = &ad9852_attribute_group;
+       st->idev->dev_data = (void *)(st);
+       st->idev->driver_module = THIS_MODULE;
+       st->idev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(st->idev);
+       if (ret)
+               goto error_free_dev;
+       spi->max_speed_hz = 2000000;
+       spi->mode = SPI_MODE_3;
+       spi->bits_per_word = 8;
+       spi_setup(spi);
+       ad9852_init(st);
+       return 0;
+
+error_free_dev:
+       iio_free_device(st->idev);
+error_free_st:
+       kfree(st);
+error_ret:
+       return ret;
+}
+
+static int __devexit ad9852_remove(struct spi_device *spi)
+{
+       struct ad9852_state *st = spi_get_drvdata(spi);
+
+       iio_device_unregister(st->idev);
+       kfree(st);
+
+       return 0;
+}
+
+static struct spi_driver ad9852_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = ad9852_probe,
+       .remove = __devexit_p(ad9852_remove),
+};
+
+static __init int ad9852_spi_init(void)
+{
+       return spi_register_driver(&ad9852_driver);
+}
+module_init(ad9852_spi_init);
+
+static __exit void ad9852_spi_exit(void)
+{
+       spi_unregister_driver(&ad9852_driver);
+}
+module_exit(ad9852_spi_exit);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad9852 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/ad9910.c b/drivers/staging/iio/dds/ad9910.c
new file mode 100644 (file)
index 0000000..c59b407
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad9910
+ *
+ * Copyright (c) 2010 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad9910"
+
+#define CFR1 0x0
+#define CFR2 0x1
+#define CFR3 0x2
+
+#define AUXDAC 0x3
+#define IOUPD 0x4
+#define FTW 0x7
+#define POW 0x8
+#define ASF 0x9
+#define MULTC 0x0A
+#define DIG_RAMPL 0x0B
+#define DIG_RAMPS 0x0C
+#define DIG_RAMPR 0x0D
+#define SIN_TONEP0 0x0E
+#define SIN_TONEP1 0x0F
+#define SIN_TONEP2 0x10
+#define SIN_TONEP3 0x11
+#define SIN_TONEP4 0x12
+#define SIN_TONEP5 0x13
+#define SIN_TONEP6 0x14
+#define SIN_TONEP7 0x15
+
+#define RAM_ENABLE     (1 << 7)
+
+#define MANUAL_OSK     (1 << 7)
+#define INVSIC         (1 << 6)
+#define DDS_SINEOP     (1)
+
+#define AUTO_OSK       (1)
+#define OSKEN          (1 << 1)
+#define LOAD_ARR       (1 << 2)
+#define CLR_PHA                (1 << 3)
+#define CLR_DIG                (1 << 4)
+#define ACLR_PHA       (1 << 5)
+#define ACLR_DIG       (1 << 6)
+#define LOAD_LRR       (1 << 7)
+
+#define LSB_FST                (1)
+#define SDIO_IPT       (1 << 1)
+#define EXT_PWD                (1 << 3)
+#define ADAC_PWD       (1 << 4)
+#define REFCLK_PWD     (1 << 5)
+#define DAC_PWD                (1 << 6)
+#define DIG_PWD                (1 << 7)
+
+#define ENA_AMP                (1)
+#define READ_FTW       (1)
+#define DIGR_LOW       (1 << 1)
+#define DIGR_HIGH      (1 << 2)
+#define DIGR_ENA       (1 << 3)
+#define SYNCCLK_ENA    (1 << 6)
+#define ITER_IOUPD     (1 << 7)
+
+#define TX_ENA         (1 << 1)
+#define PDCLK_INV      (1 << 2)
+#define PDCLK_ENB      (1 << 3)
+
+#define PARA_ENA       (1 << 4)
+#define SYNC_DIS       (1 << 5)
+#define DATA_ASS       (1 << 6)
+#define MATCH_ENA      (1 << 7)
+
+#define PLL_ENA                (1)
+#define PFD_RST                (1 << 2)
+#define REFCLK_RST     (1 << 6)
+#define REFCLK_BYP     (1 << 7)
+
+/* Register format: 1 byte addr + value */
+struct ad9910_config {
+       u8 auxdac[5];
+       u8 ioupd[5];
+       u8 ftw[5];
+       u8 pow[3];
+       u8 asf[5];
+       u8 multc[5];
+       u8 dig_rampl[9];
+       u8 dig_ramps[9];
+       u8 dig_rampr[5];
+       u8 sin_tonep0[9];
+       u8 sin_tonep1[9];
+       u8 sin_tonep2[9];
+       u8 sin_tonep3[9];
+       u8 sin_tonep4[9];
+       u8 sin_tonep5[9];
+       u8 sin_tonep6[9];
+       u8 sin_tonep7[9];
+};
+
+struct ad9910_state {
+       struct mutex lock;
+       struct iio_dev *idev;
+       struct spi_device *sdev;
+};
+
+static ssize_t ad9910_set_parameter(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf,
+                                       size_t len)
+{
+       struct spi_message msg;
+       struct spi_transfer xfer;
+       int ret;
+       struct ad9910_config *config = (struct ad9910_config *)buf;
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad9910_state *st = idev->dev_data;
+
+       xfer.len = 5;
+       xfer.tx_buf = &config->auxdac[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 5;
+       xfer.tx_buf = &config->ioupd[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 5;
+       xfer.tx_buf = &config->ftw[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 3;
+       xfer.tx_buf = &config->pow[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 5;
+       xfer.tx_buf = &config->asf[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 5;
+       xfer.tx_buf = &config->multc[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 9;
+       xfer.tx_buf = &config->dig_rampl[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 9;
+       xfer.tx_buf = &config->dig_ramps[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 5;
+       xfer.tx_buf = &config->dig_rampr[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 9;
+       xfer.tx_buf = &config->sin_tonep0[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+       xfer.len = 9;
+       xfer.tx_buf = &config->sin_tonep1[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+       xfer.len = 9;
+       xfer.tx_buf = &config->sin_tonep2[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+       xfer.len = 9;
+       xfer.tx_buf = &config->sin_tonep3[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+       xfer.len = 9;
+       xfer.tx_buf = &config->sin_tonep4[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+       xfer.len = 9;
+       xfer.tx_buf = &config->sin_tonep5[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+       xfer.len = 9;
+       xfer.tx_buf = &config->sin_tonep6[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+       xfer.len = 9;
+       xfer.tx_buf = &config->sin_tonep7[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+error_ret:
+       mutex_unlock(&st->lock);
+
+       return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9910_set_parameter, 0);
+
+static void ad9910_init(struct ad9910_state *st)
+{
+       struct spi_message msg;
+       struct spi_transfer xfer;
+       int ret;
+       u8 cfr[5];
+
+       cfr[0] = CFR1;
+       cfr[1] = 0;
+       cfr[2] = MANUAL_OSK | INVSIC | DDS_SINEOP;
+       cfr[3] = AUTO_OSK | OSKEN | ACLR_PHA | ACLR_DIG | LOAD_LRR;
+       cfr[4] = 0;
+
+       mutex_lock(&st->lock);
+
+       xfer.len = 5;
+       xfer.tx_buf = &cfr;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       cfr[0] = CFR2;
+       cfr[1] = ENA_AMP;
+       cfr[2] = READ_FTW | DIGR_ENA | ITER_IOUPD;
+       cfr[3] = TX_ENA | PDCLK_INV | PDCLK_ENB;
+       cfr[4] = PARA_ENA;
+
+       mutex_lock(&st->lock);
+
+       xfer.len = 5;
+       xfer.tx_buf = &cfr;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       cfr[0] = CFR3;
+       cfr[1] = PLL_ENA;
+       cfr[2] = 0;
+       cfr[3] = REFCLK_RST | REFCLK_BYP;
+       cfr[4] = 0;
+
+       mutex_lock(&st->lock);
+
+       xfer.len = 5;
+       xfer.tx_buf = &cfr;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+error_ret:
+       mutex_unlock(&st->lock);
+
+
+
+}
+
+static struct attribute *ad9910_attributes[] = {
+       &iio_dev_attr_dds.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ad9910_attribute_group = {
+       .name = DRV_NAME,
+       .attrs = ad9910_attributes,
+};
+
+static int __devinit ad9910_probe(struct spi_device *spi)
+{
+       struct ad9910_state *st;
+       int ret = 0;
+
+       st = kzalloc(sizeof(*st), GFP_KERNEL);
+       if (st == NULL) {
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+       spi_set_drvdata(spi, st);
+
+       mutex_init(&st->lock);
+       st->sdev = spi;
+
+       st->idev = iio_allocate_device();
+       if (st->idev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->idev->dev.parent = &spi->dev;
+       st->idev->num_interrupt_lines = 0;
+       st->idev->event_attrs = NULL;
+
+       st->idev->attrs = &ad9910_attribute_group;
+       st->idev->dev_data = (void *)(st);
+       st->idev->driver_module = THIS_MODULE;
+       st->idev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(st->idev);
+       if (ret)
+               goto error_free_dev;
+       spi->max_speed_hz = 2000000;
+       spi->mode = SPI_MODE_3;
+       spi->bits_per_word = 8;
+       spi_setup(spi);
+       ad9910_init(st);
+       return 0;
+
+error_free_dev:
+       iio_free_device(st->idev);
+error_free_st:
+       kfree(st);
+error_ret:
+       return ret;
+}
+
+static int __devexit ad9910_remove(struct spi_device *spi)
+{
+       struct ad9910_state *st = spi_get_drvdata(spi);
+
+       iio_device_unregister(st->idev);
+       kfree(st);
+
+       return 0;
+}
+
+static struct spi_driver ad9910_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = ad9910_probe,
+       .remove = __devexit_p(ad9910_remove),
+};
+
+static __init int ad9910_spi_init(void)
+{
+       return spi_register_driver(&ad9910_driver);
+}
+module_init(ad9910_spi_init);
+
+static __exit void ad9910_spi_exit(void)
+{
+       spi_unregister_driver(&ad9910_driver);
+}
+module_exit(ad9910_spi_exit);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad9910 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/dds/ad9951.c b/drivers/staging/iio/dds/ad9951.c
new file mode 100644 (file)
index 0000000..bc3beff
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Driver for ADI Direct Digital Synthesis ad9951
+ *
+ * Copyright (c) 2010 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad9951"
+
+#define CFR1 0x0
+#define CFR2 0x1
+
+#define AUTO_OSK       (1)
+#define OSKEN          (1 << 1)
+#define LOAD_ARR       (1 << 2)
+
+#define AUTO_SYNC      (1 << 7)
+
+#define LSB_FST                (1)
+#define SDIO_IPT       (1 << 1)
+#define CLR_PHA                (1 << 2)
+#define SINE_OPT       (1 << 4)
+#define ACLR_PHA       (1 << 5)
+
+#define VCO_RANGE      (1 << 2)
+
+#define CRS_OPT                (1 << 1)
+#define HMANU_SYNC     (1 << 2)
+#define HSPD_SYNC      (1 << 3)
+
+/* Register format: 1 byte addr + value */
+struct ad9951_config {
+       u8 asf[3];
+       u8 arr[2];
+       u8 ftw0[5];
+       u8 ftw1[3];
+};
+
+struct ad9951_state {
+       struct mutex lock;
+       struct iio_dev *idev;
+       struct spi_device *sdev;
+};
+
+static ssize_t ad9951_set_parameter(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf,
+                                       size_t len)
+{
+       struct spi_message msg;
+       struct spi_transfer xfer;
+       int ret;
+       struct ad9951_config *config = (struct ad9951_config *)buf;
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad9951_state *st = idev->dev_data;
+
+       xfer.len = 3;
+       xfer.tx_buf = &config->asf[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 2;
+       xfer.tx_buf = &config->arr[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 5;
+       xfer.tx_buf = &config->ftw0[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       xfer.len = 3;
+       xfer.tx_buf = &config->ftw1[0];
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+error_ret:
+       mutex_unlock(&st->lock);
+
+       return ret ? ret : len;
+}
+
+static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9951_set_parameter, 0);
+
+static void ad9951_init(struct ad9951_state *st)
+{
+       struct spi_message msg;
+       struct spi_transfer xfer;
+       int ret;
+       u8 cfr[5];
+
+       cfr[0] = CFR1;
+       cfr[1] = 0;
+       cfr[2] = LSB_FST | CLR_PHA | SINE_OPT | ACLR_PHA;
+       cfr[3] = AUTO_OSK | OSKEN | LOAD_ARR;
+       cfr[4] = 0;
+
+       mutex_lock(&st->lock);
+
+       xfer.len = 5;
+       xfer.tx_buf = &cfr;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+       cfr[0] = CFR2;
+       cfr[1] = VCO_RANGE;
+       cfr[2] = HSPD_SYNC;
+       cfr[3] = 0;
+
+       mutex_lock(&st->lock);
+
+       xfer.len = 4;
+       xfer.tx_buf = &cfr;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+
+error_ret:
+       mutex_unlock(&st->lock);
+
+
+
+}
+
+static struct attribute *ad9951_attributes[] = {
+       &iio_dev_attr_dds.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ad9951_attribute_group = {
+       .name = DRV_NAME,
+       .attrs = ad9951_attributes,
+};
+
+static int __devinit ad9951_probe(struct spi_device *spi)
+{
+       struct ad9951_state *st;
+       int ret = 0;
+
+       st = kzalloc(sizeof(*st), GFP_KERNEL);
+       if (st == NULL) {
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+       spi_set_drvdata(spi, st);
+
+       mutex_init(&st->lock);
+       st->sdev = spi;
+
+       st->idev = iio_allocate_device();
+       if (st->idev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->idev->dev.parent = &spi->dev;
+       st->idev->num_interrupt_lines = 0;
+       st->idev->event_attrs = NULL;
+
+       st->idev->attrs = &ad9951_attribute_group;
+       st->idev->dev_data = (void *)(st);
+       st->idev->driver_module = THIS_MODULE;
+       st->idev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(st->idev);
+       if (ret)
+               goto error_free_dev;
+       spi->max_speed_hz = 2000000;
+       spi->mode = SPI_MODE_3;
+       spi->bits_per_word = 8;
+       spi_setup(spi);
+       ad9951_init(st);
+       return 0;
+
+error_free_dev:
+       iio_free_device(st->idev);
+error_free_st:
+       kfree(st);
+error_ret:
+       return ret;
+}
+
+static int __devexit ad9951_remove(struct spi_device *spi)
+{
+       struct ad9951_state *st = spi_get_drvdata(spi);
+
+       iio_device_unregister(st->idev);
+       kfree(st);
+
+       return 0;
+}
+
+static struct spi_driver ad9951_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = ad9951_probe,
+       .remove = __devexit_p(ad9951_remove),
+};
+
+static __init int ad9951_spi_init(void)
+{
+       return spi_register_driver(&ad9951_driver);
+}
+module_init(ad9951_spi_init);
+
+static __exit void ad9951_spi_exit(void)
+{
+       spi_unregister_driver(&ad9951_driver);
+}
+module_exit(ad9951_spi_exit);
+
+MODULE_AUTHOR("Cliff Cai");
+MODULE_DESCRIPTION("Analog Devices ad9951 driver");
+MODULE_LICENSE("GPL v2");
index c4043610c0dfc88660f28031d3d687ccb3a7efec..236f15fdbfc9cde6160a0081518b89a42c0dc410 100644 (file)
@@ -3,11 +3,45 @@
 #
 comment "Digital gyroscope sensors"
 
+config ADIS16060
+       tristate "Analog Devices ADIS16060 Yaw Rate Gyroscope with SPI driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices adis16060 wide bandwidth
+         yaw rate gyroscope with SPI.
+
+config ADIS16080
+       tristate "Analog Devices ADIS16080/100 Yaw Rate Gyroscope with SPI driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices adis16080/100 Yaw Rate
+         Gyroscope with SPI.
+
+config ADIS16130
+       tristate "Analog Devices ADIS16130 High Precision Angular Rate Sensor driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices ADIS16130 High Precision
+         Angular Rate Sensor driver.
+
 config ADIS16260
-       tristate "Analog Devices ADIS16260/5 Digital Gyroscope Sensor SPI driver"
+       tristate "Analog Devices ADIS16260 ADIS16265 Digital Gyroscope Sensor SPI driver"
        depends on SPI
        select IIO_TRIGGER if IIO_RING_BUFFER
        select IIO_SW_RING if IIO_RING_BUFFER
        help
-         Say yes here to build support for Analog Devices adis16260/5
+         Say yes here to build support for Analog Devices ADIS16260 ADIS16265
          programmable digital gyroscope sensor.
+
+         This driver can also be built as a module.  If so, the module
+         will be called adis16260.
+
+config ADIS16251
+       tristate "Analog Devices ADIS16251 Digital Gyroscope Sensor SPI driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices adis16261 programmable
+         digital gyroscope sensor.
+
+         This driver can also be built as a module.  If so, the module
+         will be called adis16251.
index b5f0dc01122c8b149fc9c42b0efc8c6e6529684d..2764c15025a512ff07884f9a1c2f070b23286420 100644 (file)
@@ -2,6 +2,18 @@
 # Makefile for digital gyroscope sensor drivers
 #
 
+adis16060-y             := adis16060_core.o
+obj-$(CONFIG_ADIS16060) += adis16060.o
+
+adis16080-y             := adis16080_core.o
+obj-$(CONFIG_ADIS16080) += adis16080.o
+
+adis16130-y             := adis16130_core.o
+obj-$(CONFIG_ADIS16130) += adis16130.o
+
 adis16260-y             := adis16260_core.o
 adis16260-$(CONFIG_IIO_RING_BUFFER) += adis16260_ring.o adis16260_trigger.o
 obj-$(CONFIG_ADIS16260) += adis16260.o
+
+adis16251-y             := adis16251_core.o
+obj-$(CONFIG_ADIS16251) += adis16251.o
diff --git a/drivers/staging/iio/gyro/adis16060.h b/drivers/staging/iio/gyro/adis16060.h
new file mode 100644 (file)
index 0000000..5c00e53
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef SPI_ADIS16060_H_
+#define SPI_ADIS16060_H_
+
+#define ADIS16060_GYRO       0x20 /* Measure Angular Rate (Gyro) */
+#define ADIS16060_SUPPLY_OUT 0x10 /* Measure Temperature */
+#define ADIS16060_AIN2       0x80 /* Measure AIN2 */
+#define ADIS16060_AIN1       0x40 /* Measure AIN1 */
+#define ADIS16060_TEMP_OUT   0x22 /* Set Positive Self-Test and Output for Angular Rate */
+#define ADIS16060_ANGL_OUT   0x21 /* Set Negative Self-Test and Output for Angular Rate */
+
+#define ADIS16060_MAX_TX     3
+#define ADIS16060_MAX_RX     3
+
+/**
+ * struct adis16060_state - device instance specific data
+ * @us_w:                      actual spi_device to write data
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter:             used to check if new interrupt has been triggered
+ * @last_timestamp:    passing timestamp from th to bh of interrupt handler
+ * @indio_dev:         industrial I/O device structure
+ * @trig:              data ready trigger registered with iio
+ * @tx:                        transmit buffer
+ * @rx:                        recieve buffer
+ * @buf_lock:          mutex to protect tx and rx
+ **/
+struct adis16060_state {
+       struct spi_device               *us_w;
+       struct spi_device               *us_r;
+       struct work_struct              work_trigger_to_ring;
+       s64                             last_timestamp;
+       struct iio_dev                  *indio_dev;
+       struct iio_trigger              *trig;
+       u8                              *tx;
+       u8                              *rx;
+       struct mutex                    buf_lock;
+};
+
+#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
+
+enum adis16060_scan {
+       ADIS16060_SCAN_GYRO,
+       ADIS16060_SCAN_TEMP,
+       ADIS16060_SCAN_ADC_1,
+       ADIS16060_SCAN_ADC_2,
+};
+
+void adis16060_remove_trigger(struct iio_dev *indio_dev);
+int adis16060_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t adis16060_read_data_from_ring(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf);
+
+
+int adis16060_configure_ring(struct iio_dev *indio_dev);
+void adis16060_unconfigure_ring(struct iio_dev *indio_dev);
+
+int adis16060_initialize_ring(struct iio_ring_buffer *ring);
+void adis16060_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void adis16060_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16060_probe_trigger(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline ssize_t
+adis16060_read_data_from_ring(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       return 0;
+}
+
+static int adis16060_configure_ring(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline void adis16060_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16060_initialize_ring(struct iio_ring_buffer *ring)
+{
+       return 0;
+}
+
+static inline void adis16060_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+
+#endif /* CONFIG_IIO_RING_BUFFER */
+#endif /* SPI_ADIS16060_H_ */
diff --git a/drivers/staging/iio/gyro/adis16060_core.c b/drivers/staging/iio/gyro/adis16060_core.c
new file mode 100644 (file)
index 0000000..fc48aca
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * ADIS16060 Wide Bandwidth Yaw Rate Gyroscope with SPI driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "gyro.h"
+#include "../adc/adc.h"
+
+#include "adis16060.h"
+
+#define DRIVER_NAME            "adis16060"
+
+struct adis16060_state *adis16060_st;
+
+int adis16060_spi_write(struct device *dev,
+               u8 val)
+{
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16060_state *st = iio_dev_get_devdata(indio_dev);
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = 0;
+       st->tx[1] = 0;
+       st->tx[2] = val; /* The last 8 bits clocked in are latched */
+
+       ret = spi_write(st->us_w, st->tx, 3);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+int adis16060_spi_read(struct device *dev,
+               u16 *val)
+{
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16060_state *st = iio_dev_get_devdata(indio_dev);
+
+       mutex_lock(&st->buf_lock);
+
+       ret = spi_read(st->us_r, st->rx, 3);
+
+       /* The internal successive approximation ADC begins the conversion process
+        * on the falling edge of MSEL1 and starts to place data MSB first on the
+        * DOUT line at the 6th falling edge of SCLK
+        */
+       if (ret == 0)
+               *val = ((st->rx[0] & 0x3) << 12) | (st->rx[1] << 4) | ((st->rx[2] >> 4) & 0xF);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static ssize_t adis16060_read(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       u16 val;
+       ssize_t ret;
+
+       /* Take the iio_dev status lock */
+       mutex_lock(&indio_dev->mlock);
+       ret =  adis16060_spi_read(dev, &val);
+       mutex_unlock(&indio_dev->mlock);
+
+       if (ret == 0)
+               return sprintf(buf, "%d\n", val);
+       else
+               return ret;
+}
+
+static ssize_t adis16060_write(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       int ret;
+       long val;
+
+       ret = strict_strtol(buf, 16, &val);
+       if (ret)
+               goto error_ret;
+       ret = adis16060_spi_write(dev, val);
+
+error_ret:
+       return ret ? ret : len;
+}
+
+#define IIO_DEV_ATTR_IN(_show)                         \
+       IIO_DEVICE_ATTR(in, S_IRUGO, _show, NULL, 0)
+
+#define IIO_DEV_ATTR_OUT(_store)                               \
+       IIO_DEVICE_ATTR(out, S_IRUGO, NULL, _store, 0)
+
+static IIO_DEV_ATTR_IN(adis16060_read);
+static IIO_DEV_ATTR_OUT(adis16060_write);
+
+static IIO_CONST_ATTR(name, "adis16060");
+
+static struct attribute *adis16060_event_attributes[] = {
+       NULL
+};
+
+static struct attribute_group adis16060_event_attribute_group = {
+       .attrs = adis16060_event_attributes,
+};
+
+static struct attribute *adis16060_attributes[] = {
+       &iio_dev_attr_in.dev_attr.attr,
+       &iio_dev_attr_out.dev_attr.attr,
+       &iio_const_attr_name.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group adis16060_attribute_group = {
+       .attrs = adis16060_attributes,
+};
+
+static int __devinit adis16060_r_probe(struct spi_device *spi)
+{
+       int ret, regdone = 0;
+       struct adis16060_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+       if (!st) {
+               ret =  -ENOMEM;
+               goto error_ret;
+       }
+       /* this is only used for removal purposes */
+       spi_set_drvdata(spi, st);
+
+       /* Allocate the comms buffers */
+       st->rx = kzalloc(sizeof(*st->rx)*ADIS16060_MAX_RX, GFP_KERNEL);
+       if (st->rx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->tx = kzalloc(sizeof(*st->tx)*ADIS16060_MAX_TX, GFP_KERNEL);
+       if (st->tx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_rx;
+       }
+       st->us_r = spi;
+       mutex_init(&st->buf_lock);
+       /* setup the industrialio driver allocated elements */
+       st->indio_dev = iio_allocate_device();
+       if (st->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_tx;
+       }
+
+       st->indio_dev->dev.parent = &spi->dev;
+       st->indio_dev->num_interrupt_lines = 1;
+       st->indio_dev->event_attrs = &adis16060_event_attribute_group;
+       st->indio_dev->attrs = &adis16060_attribute_group;
+       st->indio_dev->dev_data = (void *)(st);
+       st->indio_dev->driver_module = THIS_MODULE;
+       st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = adis16060_configure_ring(st->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       ret = iio_device_register(st->indio_dev);
+       if (ret)
+               goto error_unreg_ring_funcs;
+       regdone = 1;
+
+       ret = adis16060_initialize_ring(st->indio_dev->ring);
+       if (ret) {
+               printk(KERN_ERR "failed to initialize the ring\n");
+               goto error_unreg_ring_funcs;
+       }
+
+       if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) {
+               ret = iio_register_interrupt_line(spi->irq,
+                               st->indio_dev,
+                               0,
+                               IRQF_TRIGGER_RISING,
+                               "adis16060");
+               if (ret)
+                       goto error_uninitialize_ring;
+
+               ret = adis16060_probe_trigger(st->indio_dev);
+               if (ret)
+                       goto error_unregister_line;
+       }
+
+       adis16060_st = st;
+       return 0;
+
+error_unregister_line:
+       if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+               iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+       adis16060_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+       adis16060_unconfigure_ring(st->indio_dev);
+error_free_dev:
+       if (regdone)
+               iio_device_unregister(st->indio_dev);
+       else
+               iio_free_device(st->indio_dev);
+error_free_tx:
+       kfree(st->tx);
+error_free_rx:
+       kfree(st->rx);
+error_free_st:
+       kfree(st);
+error_ret:
+       return ret;
+}
+
+/* fixme, confirm ordering in this function */
+static int adis16060_r_remove(struct spi_device *spi)
+{
+       struct adis16060_state *st = spi_get_drvdata(spi);
+       struct iio_dev *indio_dev = st->indio_dev;
+
+       flush_scheduled_work();
+
+       adis16060_remove_trigger(indio_dev);
+       if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
+               iio_unregister_interrupt_line(indio_dev, 0);
+
+       adis16060_uninitialize_ring(indio_dev->ring);
+       adis16060_unconfigure_ring(indio_dev);
+       iio_device_unregister(indio_dev);
+       kfree(st->tx);
+       kfree(st->rx);
+       kfree(st);
+
+       return 0;
+}
+
+static int __devinit adis16060_w_probe(struct spi_device *spi)
+{
+       int ret;
+       struct adis16060_state *st = adis16060_st;
+       if (!st) {
+               ret =  -ENODEV;
+               goto error_ret;
+       }
+       spi_set_drvdata(spi, st);
+       st->us_w = spi;
+       return 0;
+
+error_ret:
+       return ret;
+}
+
+static int adis16060_w_remove(struct spi_device *spi)
+{
+       return 0;
+}
+
+static struct spi_driver adis16060_r_driver = {
+       .driver = {
+               .name = "adis16060_r",
+               .owner = THIS_MODULE,
+       },
+       .probe = adis16060_r_probe,
+       .remove = __devexit_p(adis16060_r_remove),
+};
+
+static struct spi_driver adis16060_w_driver = {
+       .driver = {
+               .name = "adis16060_w",
+               .owner = THIS_MODULE,
+       },
+       .probe = adis16060_w_probe,
+       .remove = __devexit_p(adis16060_w_remove),
+};
+
+static __init int adis16060_init(void)
+{
+       int ret;
+
+       ret = spi_register_driver(&adis16060_r_driver);
+       if (ret < 0)
+               return ret;
+
+       ret = spi_register_driver(&adis16060_w_driver);
+       if (ret < 0) {
+               spi_unregister_driver(&adis16060_r_driver);
+               return ret;
+       }
+
+       return 0;
+}
+module_init(adis16060_init);
+
+static __exit void adis16060_exit(void)
+{
+       spi_unregister_driver(&adis16060_w_driver);
+       spi_unregister_driver(&adis16060_r_driver);
+}
+module_exit(adis16060_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADIS16060 Yaw Rate Gyroscope with SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/gyro/adis16080.h b/drivers/staging/iio/gyro/adis16080.h
new file mode 100644 (file)
index 0000000..3fcbe67
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef SPI_ADIS16080_H_
+#define SPI_ADIS16080_H_
+
+#define ADIS16080_DIN_CODE   4 /* Output data format setting. 0: Twos complement. 1: Offset binary. */
+#define ADIS16080_DIN_GYRO   (0 << 10) /* Gyroscope output */
+#define ADIS16080_DIN_TEMP   (1 << 10) /* Temperature output */
+#define ADIS16080_DIN_AIN1   (2 << 10)
+#define ADIS16080_DIN_AIN2   (3 << 10)
+#define ADIS16080_DIN_WRITE  (1 << 15) /* 1: Write contents on DIN to control register.
+                                       * 0: No changes to control register.
+                                       */
+
+#define ADIS16080_MAX_TX     2
+#define ADIS16080_MAX_RX     2
+
+/**
+ * struct adis16080_state - device instance specific data
+ * @us:                        actual spi_device to write data
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter:             used to check if new interrupt has been triggered
+ * @last_timestamp:    passing timestamp from th to bh of interrupt handler
+ * @indio_dev:         industrial I/O device structure
+ * @trig:              data ready trigger registered with iio
+ * @tx:                        transmit buffer
+ * @rx:                        recieve buffer
+ * @buf_lock:          mutex to protect tx and rx
+ **/
+struct adis16080_state {
+       struct spi_device               *us;
+       struct work_struct              work_trigger_to_ring;
+       s64                             last_timestamp;
+       struct iio_dev                  *indio_dev;
+       struct iio_trigger              *trig;
+       u8                              *tx;
+       u8                              *rx;
+       struct mutex                    buf_lock;
+};
+
+#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
+
+enum adis16080_scan {
+       ADIS16080_SCAN_GYRO,
+       ADIS16080_SCAN_TEMP,
+       ADIS16080_SCAN_ADC_1,
+       ADIS16080_SCAN_ADC_2,
+};
+
+void adis16080_remove_trigger(struct iio_dev *indio_dev);
+int adis16080_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t adis16080_read_data_from_ring(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf);
+
+
+int adis16080_configure_ring(struct iio_dev *indio_dev);
+void adis16080_unconfigure_ring(struct iio_dev *indio_dev);
+
+int adis16080_initialize_ring(struct iio_ring_buffer *ring);
+void adis16080_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void adis16080_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16080_probe_trigger(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline ssize_t
+adis16080_read_data_from_ring(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       return 0;
+}
+
+static int adis16080_configure_ring(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline void adis16080_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16080_initialize_ring(struct iio_ring_buffer *ring)
+{
+       return 0;
+}
+
+static inline void adis16080_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+
+#endif /* CONFIG_IIO_RING_BUFFER */
+#endif /* SPI_ADIS16080_H_ */
diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/staging/iio/gyro/adis16080_core.c
new file mode 100644 (file)
index 0000000..0efb768
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * ADIS16080/100 Yaw Rate Gyroscope with SPI driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "gyro.h"
+#include "../adc/adc.h"
+
+#include "adis16080.h"
+
+#define DRIVER_NAME            "adis16080"
+
+struct adis16080_state *adis16080_st;
+
+int adis16080_spi_write(struct device *dev,
+               u16 val)
+{
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16080_state *st = iio_dev_get_devdata(indio_dev);
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = val >> 8;
+       st->tx[1] = val;
+
+       ret = spi_write(st->us, st->tx, 2);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+int adis16080_spi_read(struct device *dev,
+               u16 *val)
+{
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16080_state *st = iio_dev_get_devdata(indio_dev);
+
+       mutex_lock(&st->buf_lock);
+
+       ret = spi_read(st->us, st->rx, 2);
+
+       if (ret == 0)
+               *val = ((st->rx[0] & 0xF) << 8) | st->rx[1];
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static ssize_t adis16080_read(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       u16 val;
+       ssize_t ret;
+
+       /* Take the iio_dev status lock */
+       mutex_lock(&indio_dev->mlock);
+       ret =  adis16080_spi_read(dev, &val);
+       mutex_unlock(&indio_dev->mlock);
+
+       if (ret == 0)
+               return sprintf(buf, "%d\n", val);
+       else
+               return ret;
+}
+
+static ssize_t adis16080_write(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       int ret;
+       long val;
+
+       ret = strict_strtol(buf, 16, &val);
+       if (ret)
+               goto error_ret;
+       ret = adis16080_spi_write(dev, val);
+
+error_ret:
+       return ret ? ret : len;
+}
+
+#define IIO_DEV_ATTR_IN(_show)                         \
+       IIO_DEVICE_ATTR(in, S_IRUGO, _show, NULL, 0)
+
+#define IIO_DEV_ATTR_OUT(_store)                               \
+       IIO_DEVICE_ATTR(out, S_IRUGO, NULL, _store, 0)
+
+static IIO_DEV_ATTR_IN(adis16080_read);
+static IIO_DEV_ATTR_OUT(adis16080_write);
+
+static IIO_CONST_ATTR(name, "adis16080");
+
+static struct attribute *adis16080_event_attributes[] = {
+       NULL
+};
+
+static struct attribute_group adis16080_event_attribute_group = {
+       .attrs = adis16080_event_attributes,
+};
+
+static struct attribute *adis16080_attributes[] = {
+       &iio_dev_attr_in.dev_attr.attr,
+       &iio_dev_attr_out.dev_attr.attr,
+       &iio_const_attr_name.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group adis16080_attribute_group = {
+       .attrs = adis16080_attributes,
+};
+
+static int __devinit adis16080_probe(struct spi_device *spi)
+{
+       int ret, regdone = 0;
+       struct adis16080_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+       if (!st) {
+               ret =  -ENOMEM;
+               goto error_ret;
+       }
+       /* this is only used for removal purposes */
+       spi_set_drvdata(spi, st);
+
+       /* Allocate the comms buffers */
+       st->rx = kzalloc(sizeof(*st->rx)*ADIS16080_MAX_RX, GFP_KERNEL);
+       if (st->rx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->tx = kzalloc(sizeof(*st->tx)*ADIS16080_MAX_TX, GFP_KERNEL);
+       if (st->tx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_rx;
+       }
+       st->us = spi;
+       mutex_init(&st->buf_lock);
+       /* setup the industrialio driver allocated elements */
+       st->indio_dev = iio_allocate_device();
+       if (st->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_tx;
+       }
+
+       st->indio_dev->dev.parent = &spi->dev;
+       st->indio_dev->num_interrupt_lines = 1;
+       st->indio_dev->event_attrs = &adis16080_event_attribute_group;
+       st->indio_dev->attrs = &adis16080_attribute_group;
+       st->indio_dev->dev_data = (void *)(st);
+       st->indio_dev->driver_module = THIS_MODULE;
+       st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = adis16080_configure_ring(st->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       ret = iio_device_register(st->indio_dev);
+       if (ret)
+               goto error_unreg_ring_funcs;
+       regdone = 1;
+
+       ret = adis16080_initialize_ring(st->indio_dev->ring);
+       if (ret) {
+               printk(KERN_ERR "failed to initialize the ring\n");
+               goto error_unreg_ring_funcs;
+       }
+
+       if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) {
+               ret = iio_register_interrupt_line(spi->irq,
+                               st->indio_dev,
+                               0,
+                               IRQF_TRIGGER_RISING,
+                               "adis16080");
+               if (ret)
+                       goto error_uninitialize_ring;
+
+               ret = adis16080_probe_trigger(st->indio_dev);
+               if (ret)
+                       goto error_unregister_line;
+       }
+
+       adis16080_st = st;
+       return 0;
+
+error_unregister_line:
+       if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+               iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+       adis16080_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+       adis16080_unconfigure_ring(st->indio_dev);
+error_free_dev:
+       if (regdone)
+               iio_device_unregister(st->indio_dev);
+       else
+               iio_free_device(st->indio_dev);
+error_free_tx:
+       kfree(st->tx);
+error_free_rx:
+       kfree(st->rx);
+error_free_st:
+       kfree(st);
+error_ret:
+       return ret;
+}
+
+/* fixme, confirm ordering in this function */
+static int adis16080_remove(struct spi_device *spi)
+{
+       struct adis16080_state *st = spi_get_drvdata(spi);
+       struct iio_dev *indio_dev = st->indio_dev;
+
+       flush_scheduled_work();
+
+       adis16080_remove_trigger(indio_dev);
+       if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
+               iio_unregister_interrupt_line(indio_dev, 0);
+
+       adis16080_uninitialize_ring(indio_dev->ring);
+       adis16080_unconfigure_ring(indio_dev);
+       iio_device_unregister(indio_dev);
+       kfree(st->tx);
+       kfree(st->rx);
+       kfree(st);
+
+       return 0;
+}
+
+static struct spi_driver adis16080_driver = {
+       .driver = {
+               .name = "adis16080",
+               .owner = THIS_MODULE,
+       },
+       .probe = adis16080_probe,
+       .remove = __devexit_p(adis16080_remove),
+};
+
+static __init int adis16080_init(void)
+{
+       return spi_register_driver(&adis16080_driver);
+}
+module_init(adis16080_init);
+
+static __exit void adis16080_exit(void)
+{
+       spi_unregister_driver(&adis16080_driver);
+}
+module_exit(adis16080_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADIS16080/100 Yaw Rate Gyroscope with SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/gyro/adis16130.h b/drivers/staging/iio/gyro/adis16130.h
new file mode 100644 (file)
index 0000000..ab80ef6
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef SPI_ADIS16130_H_
+#define SPI_ADIS16130_H_
+
+#define ADIS16130_CON         0x0
+#define ADIS16130_CON_RD      (1 << 6)
+#define ADIS16130_IOP         0x1
+#define ADIS16130_IOP_ALL_RDY (1 << 3) /* 1 = data-ready signal low when unread data on all channels; */
+#define ADIS16130_IOP_SYNC    (1 << 0) /* 1 = synchronization enabled */
+#define ADIS16130_RATEDATA    0x8 /* Gyroscope output, rate of rotation */
+#define ADIS16130_TEMPDATA    0xA /* Temperature output */
+#define ADIS16130_RATECS      0x28 /* Gyroscope channel setup */
+#define ADIS16130_RATECS_EN   (1 << 3) /* 1 = channel enable; */
+#define ADIS16130_TEMPCS      0x2A /* Temperature channel setup */
+#define ADIS16130_TEMPCS_EN   (1 << 3)
+#define ADIS16130_RATECONV    0x30
+#define ADIS16130_TEMPCONV    0x32
+#define ADIS16130_MODE        0x38
+#define ADIS16130_MODE_24BIT  (1 << 1) /* 1 = 24-bit resolution; */
+
+#define ADIS16130_MAX_TX     4
+#define ADIS16130_MAX_RX     4
+
+/**
+ * struct adis16130_state - device instance specific data
+ * @us:                        actual spi_device to write data
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter:             used to check if new interrupt has been triggered
+ * @last_timestamp:    passing timestamp from th to bh of interrupt handler
+ * @indio_dev:         industrial I/O device structure
+ * @trig:              data ready trigger registered with iio
+ * @tx:                        transmit buffer
+ * @rx:                        recieve buffer
+ * @buf_lock:          mutex to protect tx and rx
+ **/
+struct adis16130_state {
+       struct spi_device               *us;
+       struct work_struct              work_trigger_to_ring;
+       s64                             last_timestamp;
+       struct iio_dev                  *indio_dev;
+       struct iio_trigger              *trig;
+       u8                              *tx;
+       u8                              *rx;
+       u32                             mode; /* 1: 24bits mode 0:16bits mode */
+       struct mutex                    buf_lock;
+};
+
+#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
+
+enum adis16130_scan {
+       ADIS16130_SCAN_GYRO,
+       ADIS16130_SCAN_TEMP,
+};
+
+void adis16130_remove_trigger(struct iio_dev *indio_dev);
+int adis16130_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t adis16130_read_data_from_ring(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf);
+
+
+int adis16130_configure_ring(struct iio_dev *indio_dev);
+void adis16130_unconfigure_ring(struct iio_dev *indio_dev);
+
+int adis16130_initialize_ring(struct iio_ring_buffer *ring);
+void adis16130_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void adis16130_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16130_probe_trigger(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline ssize_t
+adis16130_read_data_from_ring(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       return 0;
+}
+
+static int adis16130_configure_ring(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline void adis16130_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16130_initialize_ring(struct iio_ring_buffer *ring)
+{
+       return 0;
+}
+
+static inline void adis16130_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+
+#endif /* CONFIG_IIO_RING_BUFFER */
+#endif /* SPI_ADIS16130_H_ */
diff --git a/drivers/staging/iio/gyro/adis16130_core.c b/drivers/staging/iio/gyro/adis16130_core.c
new file mode 100644 (file)
index 0000000..49ffc7b
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * ADIS16130 Digital Output, High Precision Angular Rate Sensor driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "gyro.h"
+#include "../adc/adc.h"
+
+#include "adis16130.h"
+
+#define DRIVER_NAME            "adis16130"
+
+struct adis16130_state *adis16130_st;
+
+int adis16130_spi_write(struct device *dev, u8 reg_addr,
+               u8 val)
+{
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16130_state *st = iio_dev_get_devdata(indio_dev);
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = reg_addr;
+       st->tx[1] = val;
+
+       ret = spi_write(st->us, st->tx, 2);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+int adis16130_spi_read(struct device *dev, u8 reg_addr,
+               u32 *val)
+{
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16130_state *st = iio_dev_get_devdata(indio_dev);
+
+       mutex_lock(&st->buf_lock);
+
+       st->tx[0] = ADIS16130_CON_RD | reg_addr;
+       if (st->mode)
+               ret = spi_read(st->us, st->rx, 4);
+       else
+               ret = spi_read(st->us, st->rx, 3);
+
+       if (ret == 0) {
+               if (st->mode)
+                       *val = (st->rx[1] << 16) | (st->rx[2] << 8) | st->rx[3];
+               else
+                       *val = (st->rx[1] << 8) | st->rx[2];
+       }
+
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static ssize_t adis16130_gyro_read(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       u32 val;
+       ssize_t ret;
+
+       /* Take the iio_dev status lock */
+       mutex_lock(&indio_dev->mlock);
+       ret =  adis16130_spi_read(dev, ADIS16130_RATEDATA, &val);
+       mutex_unlock(&indio_dev->mlock);
+
+       if (ret == 0)
+               return sprintf(buf, "%d\n", val);
+       else
+               return ret;
+}
+
+static ssize_t adis16130_temp_read(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       u32 val;
+       ssize_t ret;
+
+       /* Take the iio_dev status lock */
+       mutex_lock(&indio_dev->mlock);
+       ret =  adis16130_spi_read(dev, ADIS16130_TEMPDATA, &val);
+       mutex_unlock(&indio_dev->mlock);
+
+       if (ret == 0)
+               return sprintf(buf, "%d\n", val);
+       else
+               return ret;
+}
+
+static ssize_t adis16130_bitsmode_read(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16130_state *st = iio_dev_get_devdata(indio_dev);
+
+       return sprintf(buf, "%d\n", st->mode);
+}
+
+static ssize_t adis16130_bitsmode_write(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       int ret;
+       long val;
+
+       ret = strict_strtol(buf, 16, &val);
+       if (ret)
+               goto error_ret;
+       ret = adis16130_spi_write(dev, ADIS16130_MODE, !!val);
+
+error_ret:
+       return ret ? ret : len;
+}
+
+static IIO_DEV_ATTR_TEMP_RAW(adis16130_temp_read);
+
+static IIO_CONST_ATTR(name, "adis16130");
+
+static IIO_DEV_ATTR_GYRO(adis16130_gyro_read,
+               ADIS16130_RATEDATA);
+
+#define IIO_DEV_ATTR_BITS_MODE(_mode, _show, _store, _addr)    \
+       IIO_DEVICE_ATTR(bits_mode, _mode, _show, _store, _addr)
+
+static IIO_DEV_ATTR_BITS_MODE(S_IWUSR | S_IRUGO, adis16130_bitsmode_read, adis16130_bitsmode_write,
+                       ADIS16130_MODE);
+
+static struct attribute *adis16130_event_attributes[] = {
+       NULL
+};
+
+static struct attribute_group adis16130_event_attribute_group = {
+       .attrs = adis16130_event_attributes,
+};
+
+static struct attribute *adis16130_attributes[] = {
+       &iio_dev_attr_temp_raw.dev_attr.attr,
+       &iio_const_attr_name.dev_attr.attr,
+       &iio_dev_attr_gyro_raw.dev_attr.attr,
+       &iio_dev_attr_bits_mode.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group adis16130_attribute_group = {
+       .attrs = adis16130_attributes,
+};
+
+static int __devinit adis16130_probe(struct spi_device *spi)
+{
+       int ret, regdone = 0;
+       struct adis16130_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+       if (!st) {
+               ret =  -ENOMEM;
+               goto error_ret;
+       }
+       /* this is only used for removal purposes */
+       spi_set_drvdata(spi, st);
+
+       /* Allocate the comms buffers */
+       st->rx = kzalloc(sizeof(*st->rx)*ADIS16130_MAX_RX, GFP_KERNEL);
+       if (st->rx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->tx = kzalloc(sizeof(*st->tx)*ADIS16130_MAX_TX, GFP_KERNEL);
+       if (st->tx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_rx;
+       }
+       st->us = spi;
+       mutex_init(&st->buf_lock);
+       /* setup the industrialio driver allocated elements */
+       st->indio_dev = iio_allocate_device();
+       if (st->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_tx;
+       }
+
+       st->indio_dev->dev.parent = &spi->dev;
+       st->indio_dev->num_interrupt_lines = 1;
+       st->indio_dev->event_attrs = &adis16130_event_attribute_group;
+       st->indio_dev->attrs = &adis16130_attribute_group;
+       st->indio_dev->dev_data = (void *)(st);
+       st->indio_dev->driver_module = THIS_MODULE;
+       st->indio_dev->modes = INDIO_DIRECT_MODE;
+       st->mode = 1;
+
+       ret = adis16130_configure_ring(st->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       ret = iio_device_register(st->indio_dev);
+       if (ret)
+               goto error_unreg_ring_funcs;
+       regdone = 1;
+
+       ret = adis16130_initialize_ring(st->indio_dev->ring);
+       if (ret) {
+               printk(KERN_ERR "failed to initialize the ring\n");
+               goto error_unreg_ring_funcs;
+       }
+
+       if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) {
+               ret = iio_register_interrupt_line(spi->irq,
+                               st->indio_dev,
+                               0,
+                               IRQF_TRIGGER_RISING,
+                               "adis16130");
+               if (ret)
+                       goto error_uninitialize_ring;
+
+               ret = adis16130_probe_trigger(st->indio_dev);
+               if (ret)
+                       goto error_unregister_line;
+       }
+
+       adis16130_st = st;
+       return 0;
+
+error_unregister_line:
+       if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+               iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+       adis16130_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+       adis16130_unconfigure_ring(st->indio_dev);
+error_free_dev:
+       if (regdone)
+               iio_device_unregister(st->indio_dev);
+       else
+               iio_free_device(st->indio_dev);
+error_free_tx:
+       kfree(st->tx);
+error_free_rx:
+       kfree(st->rx);
+error_free_st:
+       kfree(st);
+error_ret:
+       return ret;
+}
+
+/* fixme, confirm ordering in this function */
+static int adis16130_remove(struct spi_device *spi)
+{
+       struct adis16130_state *st = spi_get_drvdata(spi);
+       struct iio_dev *indio_dev = st->indio_dev;
+
+       flush_scheduled_work();
+
+       adis16130_remove_trigger(indio_dev);
+       if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
+               iio_unregister_interrupt_line(indio_dev, 0);
+
+       adis16130_uninitialize_ring(indio_dev->ring);
+       adis16130_unconfigure_ring(indio_dev);
+       iio_device_unregister(indio_dev);
+       kfree(st->tx);
+       kfree(st->rx);
+       kfree(st);
+
+       return 0;
+}
+
+static struct spi_driver adis16130_driver = {
+       .driver = {
+               .name = "adis16130",
+               .owner = THIS_MODULE,
+       },
+       .probe = adis16130_probe,
+       .remove = __devexit_p(adis16130_remove),
+};
+
+static __init int adis16130_init(void)
+{
+       return spi_register_driver(&adis16130_driver);
+}
+module_init(adis16130_init);
+
+static __exit void adis16130_exit(void)
+{
+       spi_unregister_driver(&adis16130_driver);
+}
+module_exit(adis16130_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADIS16130 High Precision Angular Rate Sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/gyro/adis16251.h b/drivers/staging/iio/gyro/adis16251.h
new file mode 100644 (file)
index 0000000..999db49
--- /dev/null
@@ -0,0 +1,185 @@
+#ifndef SPI_ADIS16251_H_
+#define SPI_ADIS16251_H_
+
+#define ADIS16251_STARTUP_DELAY        220 /* ms */
+
+#define ADIS16251_READ_REG(a)    a
+#define ADIS16251_WRITE_REG(a) ((a) | 0x80)
+
+#define ADIS16251_ENDURANCE  0x00 /* Flash memory write count */
+#define ADIS16251_SUPPLY_OUT 0x02 /* Power supply measurement */
+#define ADIS16251_GYRO_OUT   0x04 /* X-axis gyroscope output */
+#define ADIS16251_AUX_ADC    0x0A /* analog input channel measurement */
+#define ADIS16251_TEMP_OUT   0x0C /* internal temperature measurement */
+#define ADIS16251_ANGL_OUT   0x0E /* angle displacement */
+#define ADIS16251_GYRO_OFF   0x14 /* Calibration, offset/bias adjustment */
+#define ADIS16251_GYRO_SCALE 0x16 /* Calibration, scale adjustment */
+#define ADIS16251_ALM_MAG1   0x20 /* Alarm 1 magnitude/polarity setting */
+#define ADIS16251_ALM_MAG2   0x22 /* Alarm 2 magnitude/polarity setting */
+#define ADIS16251_ALM_SMPL1  0x24 /* Alarm 1 dynamic rate of change setting */
+#define ADIS16251_ALM_SMPL2  0x26 /* Alarm 2 dynamic rate of change setting */
+#define ADIS16251_ALM_CTRL   0x28 /* Alarm control */
+#define ADIS16251_AUX_DAC    0x30 /* Auxiliary DAC data */
+#define ADIS16251_GPIO_CTRL  0x32 /* Control, digital I/O line */
+#define ADIS16251_MSC_CTRL   0x34 /* Control, data ready, self-test settings */
+#define ADIS16251_SMPL_PRD   0x36 /* Control, internal sample rate */
+#define ADIS16251_SENS_AVG   0x38 /* Control, dynamic range, filtering */
+#define ADIS16251_SLP_CNT    0x3A /* Control, sleep mode initiation */
+#define ADIS16251_DIAG_STAT  0x3C /* Diagnostic, error flags */
+#define ADIS16251_GLOB_CMD   0x3E /* Control, global commands */
+
+#define ADIS16251_ERROR_ACTIVE                 (1<<14)
+#define ADIS16251_NEW_DATA                     (1<<14)
+
+/* MSC_CTRL */
+#define ADIS16251_MSC_CTRL_INT_SELF_TEST       (1<<10) /* Internal self-test enable */
+#define ADIS16251_MSC_CTRL_NEG_SELF_TEST       (1<<9)
+#define ADIS16251_MSC_CTRL_POS_SELF_TEST       (1<<8)
+#define ADIS16251_MSC_CTRL_DATA_RDY_EN         (1<<2)
+#define ADIS16251_MSC_CTRL_DATA_RDY_POL_HIGH   (1<<1)
+#define ADIS16251_MSC_CTRL_DATA_RDY_DIO2       (1<<0)
+
+/* SMPL_PRD */
+#define ADIS16251_SMPL_PRD_TIME_BASE   (1<<7) /* Time base (tB): 0 = 1.953 ms, 1 = 60.54 ms */
+#define ADIS16251_SMPL_PRD_DIV_MASK    0x7F
+
+/* SLP_CNT */
+#define ADIS16251_SLP_CNT_POWER_OFF     0x80
+
+/* DIAG_STAT */
+#define ADIS16251_DIAG_STAT_ALARM2     (1<<9)
+#define ADIS16251_DIAG_STAT_ALARM1     (1<<8)
+#define ADIS16251_DIAG_STAT_SELF_TEST  (1<<5)
+#define ADIS16251_DIAG_STAT_OVERFLOW   (1<<4)
+#define ADIS16251_DIAG_STAT_SPI_FAIL   (1<<3)
+#define ADIS16251_DIAG_STAT_FLASH_UPT  (1<<2)
+#define ADIS16251_DIAG_STAT_POWER_HIGH (1<<1)
+#define ADIS16251_DIAG_STAT_POWER_LOW  (1<<0)
+
+#define ADIS16251_DIAG_STAT_ERR_MASK (ADIS16261_DIAG_STAT_ALARM2 | \
+                                     ADIS16261_DIAG_STAT_ALARM1 | \
+                                     ADIS16261_DIAG_STAT_SELF_TEST | \
+                                     ADIS16261_DIAG_STAT_OVERFLOW | \
+                                     ADIS16261_DIAG_STAT_SPI_FAIL | \
+                                     ADIS16261_DIAG_STAT_FLASH_UPT | \
+                                     ADIS16261_DIAG_STAT_POWER_HIGH | \
+                                     ADIS16261_DIAG_STAT_POWER_LOW)
+
+/* GLOB_CMD */
+#define ADIS16251_GLOB_CMD_SW_RESET    (1<<7)
+#define ADIS16251_GLOB_CMD_FLASH_UPD   (1<<3)
+#define ADIS16251_GLOB_CMD_DAC_LATCH   (1<<2)
+#define ADIS16251_GLOB_CMD_FAC_CALIB   (1<<1)
+#define ADIS16251_GLOB_CMD_AUTO_NULL   (1<<0)
+
+#define ADIS16251_MAX_TX 24
+#define ADIS16251_MAX_RX 24
+
+#define ADIS16251_SPI_SLOW     (u32)(300 * 1000)
+#define ADIS16251_SPI_BURST    (u32)(1000 * 1000)
+#define ADIS16251_SPI_FAST     (u32)(2000 * 1000)
+
+/**
+ * struct adis16251_state - device instance specific data
+ * @us:                        actual spi_device
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter:             used to check if new interrupt has been triggered
+ * @last_timestamp:    passing timestamp from th to bh of interrupt handler
+ * @indio_dev:         industrial I/O device structure
+ * @trig:              data ready trigger registered with iio
+ * @tx:                        transmit buffer
+ * @rx:                        recieve buffer
+ * @buf_lock:          mutex to protect tx and rx
+ **/
+struct adis16251_state {
+       struct spi_device               *us;
+       struct work_struct              work_trigger_to_ring;
+       s64                             last_timestamp;
+       struct iio_dev                  *indio_dev;
+       struct iio_trigger              *trig;
+       u8                              *tx;
+       u8                              *rx;
+       struct mutex                    buf_lock;
+};
+
+int adis16251_spi_write_reg_8(struct device *dev,
+                             u8 reg_address,
+                             u8 val);
+
+int adis16251_spi_read_burst(struct device *dev, u8 *rx);
+
+int adis16251_spi_read_sequence(struct device *dev,
+                                     u8 *tx, u8 *rx, int num);
+
+int adis16251_set_irq(struct device *dev, bool enable);
+
+int adis16251_reset(struct device *dev);
+
+int adis16251_stop_device(struct device *dev);
+
+int adis16251_check_status(struct device *dev);
+
+#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
+
+enum adis16251_scan {
+       ADIS16251_SCAN_SUPPLY,
+       ADIS16251_SCAN_GYRO,
+       ADIS16251_SCAN_TEMP,
+       ADIS16251_SCAN_ADC_0,
+};
+
+void adis16251_remove_trigger(struct iio_dev *indio_dev);
+int adis16251_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t adis16251_read_data_from_ring(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf);
+
+
+int adis16251_configure_ring(struct iio_dev *indio_dev);
+void adis16251_unconfigure_ring(struct iio_dev *indio_dev);
+
+int adis16251_initialize_ring(struct iio_ring_buffer *ring);
+void adis16251_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void adis16251_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16251_probe_trigger(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline ssize_t
+adis16251_read_data_from_ring(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       return 0;
+}
+
+static int adis16251_configure_ring(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline void adis16251_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+
+static inline int adis16251_initialize_ring(struct iio_ring_buffer *ring)
+{
+       return 0;
+}
+
+static inline void adis16251_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+
+#endif /* CONFIG_IIO_RING_BUFFER */
+#endif /* SPI_ADIS16251_H_ */
diff --git a/drivers/staging/iio/gyro/adis16251_core.c b/drivers/staging/iio/gyro/adis16251_core.c
new file mode 100644 (file)
index 0000000..a0d400f
--- /dev/null
@@ -0,0 +1,777 @@
+/*
+ * ADIS16251 Programmable Digital Gyroscope Sensor Driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "gyro.h"
+#include "../adc/adc.h"
+
+#include "adis16251.h"
+
+#define DRIVER_NAME            "adis16251"
+
+/* At the moment the spi framework doesn't allow global setting of cs_change.
+ * It's in the likely to be added comment at the top of spi.h.
+ * This means that use cannot be made of spi_write etc.
+ */
+
+/**
+ * adis16251_spi_write_reg_8() - write single byte to a register
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the register to be written
+ * @val: the value to write
+ **/
+int adis16251_spi_write_reg_8(struct device *dev,
+               u8 reg_address,
+               u8 val)
+{
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16251_state *st = iio_dev_get_devdata(indio_dev);
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADIS16251_WRITE_REG(reg_address);
+       st->tx[1] = val;
+
+       ret = spi_write(st->us, st->tx, 2);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+/**
+ * adis16251_spi_write_reg_16() - write 2 bytes to a pair of registers
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the lower of the two registers. Second register
+ *               is assumed to have address one greater.
+ * @val: value to be written
+ **/
+static int adis16251_spi_write_reg_16(struct device *dev,
+               u8 lower_reg_address,
+               u16 value)
+{
+       int ret;
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16251_state *st = iio_dev_get_devdata(indio_dev);
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 2,
+                       .cs_change = 1,
+               }, {
+                       .tx_buf = st->tx + 2,
+                       .bits_per_word = 8,
+                       .len = 2,
+                       .cs_change = 1,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADIS16251_WRITE_REG(lower_reg_address);
+       st->tx[1] = value & 0xFF;
+       st->tx[2] = ADIS16251_WRITE_REG(lower_reg_address + 1);
+       st->tx[3] = (value >> 8) & 0xFF;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfers[0], &msg);
+       spi_message_add_tail(&xfers[1], &msg);
+       ret = spi_sync(st->us, &msg);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+/**
+ * adis16251_spi_read_reg_16() - read 2 bytes from a 16-bit register
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @reg_address: the address of the lower of the two registers. Second register
+ *               is assumed to have address one greater.
+ * @val: somewhere to pass back the value read
+ **/
+static int adis16251_spi_read_reg_16(struct device *dev,
+               u8 lower_reg_address,
+               u16 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16251_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 2,
+                       .cs_change = 1,
+               }, {
+                       .rx_buf = st->rx,
+                       .bits_per_word = 8,
+                       .len = 2,
+                       .cs_change = 1,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADIS16251_READ_REG(lower_reg_address);
+       st->tx[1] = 0;
+       st->tx[2] = 0;
+       st->tx[3] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfers[0], &msg);
+       spi_message_add_tail(&xfers[1], &msg);
+       ret = spi_sync(st->us, &msg);
+       if (ret) {
+               dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
+                               lower_reg_address);
+               goto error_ret;
+       }
+       *val = (st->rx[0] << 8) | st->rx[1];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+/**
+ * adis16251_spi_read_burst() - read all data registers
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @rx: somewhere to pass back the value read (min size is 24 bytes)
+ **/
+int adis16251_spi_read_burst(struct device *dev, u8 *rx)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16251_state *st = iio_dev_get_devdata(indio_dev);
+       u32 old_speed_hz = st->us->max_speed_hz;
+       int ret;
+
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 2,
+                       .cs_change = 0,
+               }, {
+                       .rx_buf = rx,
+                       .bits_per_word = 8,
+                       .len = 24,
+                       .cs_change = 1,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADIS16251_READ_REG(ADIS16251_GLOB_CMD);
+       st->tx[1] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfers[0], &msg);
+       spi_message_add_tail(&xfers[1], &msg);
+
+       st->us->max_speed_hz = min(ADIS16251_SPI_BURST, old_speed_hz);
+       spi_setup(st->us);
+
+       ret = spi_sync(st->us, &msg);
+       if (ret)
+               dev_err(&st->us->dev, "problem when burst reading");
+
+       st->us->max_speed_hz = old_speed_hz;
+       spi_setup(st->us);
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+/**
+ * adis16251_spi_read_sequence() - read a sequence of 16-bit registers
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @tx: register addresses in bytes 0,2,4,6... (min size is 2*num bytes)
+ * @rx: somewhere to pass back the value read (min size is 2*num bytes)
+ **/
+int adis16251_spi_read_sequence(struct device *dev,
+               u8 *tx, u8 *rx, int num)
+{
+       struct spi_message msg;
+       struct spi_transfer *xfers;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16251_state *st = iio_dev_get_devdata(indio_dev);
+       int ret, i;
+
+       xfers = kzalloc(num + 1, GFP_KERNEL);
+       if (xfers == NULL) {
+               dev_err(&st->us->dev, "memory alloc failed");
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+
+       /* tx: |add1|addr2|addr3|...|addrN |zero|
+        * rx: |zero|res1 |res2 |...|resN-1|resN| */
+       spi_message_init(&msg);
+       for (i = 0; i < num + 1; i++) {
+               if (i > 0)
+                       xfers[i].rx_buf = st->rx + 2*(i - 1);
+               if (i < num)
+                       xfers[i].tx_buf = st->tx + 2*i;
+               xfers[i].bits_per_word = 8;
+               xfers[i].len = 2;
+               xfers[i].cs_change = 1;
+               spi_message_add_tail(&xfers[i], &msg);
+       }
+
+       mutex_lock(&st->buf_lock);
+
+       ret = spi_sync(st->us, &msg);
+       if (ret)
+               dev_err(&st->us->dev, "problem when reading sequence");
+
+       mutex_unlock(&st->buf_lock);
+       kfree(xfers);
+
+error_ret:
+       return ret;
+}
+
+static ssize_t adis16251_spi_read_signed(struct device *dev,
+               struct device_attribute *attr,
+               char *buf,
+               unsigned bits)
+{
+       int ret;
+       s16 val = 0;
+       unsigned shift = 16 - bits;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = adis16251_spi_read_reg_16(dev, this_attr->address, (u16 *)&val);
+       if (ret)
+               return ret;
+
+       if (val & ADIS16251_ERROR_ACTIVE)
+               adis16251_check_status(dev);
+       val = ((s16)(val << shift) >> shift);
+       return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t adis16251_read_12bit_unsigned(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u16 val = 0;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = adis16251_spi_read_reg_16(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       if (val & ADIS16251_ERROR_ACTIVE)
+               adis16251_check_status(dev);
+
+       return sprintf(buf, "%u\n", val & 0x0FFF);
+}
+
+static ssize_t adis16251_read_14bit_signed(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       ssize_t ret;
+
+       /* Take the iio_dev status lock */
+       mutex_lock(&indio_dev->mlock);
+       ret =  adis16251_spi_read_signed(dev, attr, buf, 14);
+       mutex_unlock(&indio_dev->mlock);
+
+       return ret;
+}
+
+static ssize_t adis16251_read_12bit_signed(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       ssize_t ret;
+
+       /* Take the iio_dev status lock */
+       mutex_lock(&indio_dev->mlock);
+       ret =  adis16251_spi_read_signed(dev, attr, buf, 12);
+       mutex_unlock(&indio_dev->mlock);
+
+       return ret;
+}
+
+static ssize_t adis16251_write_16bit(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       int ret;
+       long val;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               goto error_ret;
+       ret = adis16251_spi_write_reg_16(dev, this_attr->address, val);
+
+error_ret:
+       return ret ? ret : len;
+}
+
+static ssize_t adis16251_read_frequency(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret, len = 0;
+       u16 t;
+       int sps;
+       ret = adis16251_spi_read_reg_16(dev,
+                       ADIS16251_SMPL_PRD,
+                       &t);
+       if (ret)
+               return ret;
+       sps =  (t & ADIS16251_SMPL_PRD_TIME_BASE) ? 8 : 256;
+       sps /= (t & ADIS16251_SMPL_PRD_DIV_MASK) + 1;
+       len = sprintf(buf, "%d SPS\n", sps);
+       return len;
+}
+
+static ssize_t adis16251_write_frequency(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct adis16251_state *st = iio_dev_get_devdata(indio_dev);
+       long val;
+       int ret;
+       u8 t;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               return ret;
+
+       mutex_lock(&indio_dev->mlock);
+
+       t = (256 / val);
+       if (t > 0)
+               t--;
+       t &= ADIS16251_SMPL_PRD_DIV_MASK;
+       if ((t & ADIS16251_SMPL_PRD_DIV_MASK) >= 0x0A)
+               st->us->max_speed_hz = ADIS16251_SPI_SLOW;
+       else
+               st->us->max_speed_hz = ADIS16251_SPI_FAST;
+
+       ret = adis16251_spi_write_reg_8(dev,
+                       ADIS16251_SMPL_PRD,
+                       t);
+
+       mutex_unlock(&indio_dev->mlock);
+
+       return ret ? ret : len;
+}
+
+static ssize_t adis16251_write_reset(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf, size_t len)
+{
+       if (len < 1)
+               return -1;
+       switch (buf[0]) {
+       case '1':
+       case 'y':
+       case 'Y':
+               return adis16251_reset(dev);
+       }
+       return -1;
+}
+
+
+
+int adis16251_set_irq(struct device *dev, bool enable)
+{
+       int ret;
+       u16 msc;
+       ret = adis16251_spi_read_reg_16(dev, ADIS16251_MSC_CTRL, &msc);
+       if (ret)
+               goto error_ret;
+
+       msc |= ADIS16251_MSC_CTRL_DATA_RDY_POL_HIGH;
+       if (enable)
+               msc |= ADIS16251_MSC_CTRL_DATA_RDY_EN;
+       else
+               msc &= ~ADIS16251_MSC_CTRL_DATA_RDY_EN;
+
+       ret = adis16251_spi_write_reg_16(dev, ADIS16251_MSC_CTRL, msc);
+       if (ret)
+               goto error_ret;
+
+error_ret:
+       return ret;
+}
+
+int adis16251_reset(struct device *dev)
+{
+       int ret;
+       ret = adis16251_spi_write_reg_8(dev,
+                       ADIS16251_GLOB_CMD,
+                       ADIS16251_GLOB_CMD_SW_RESET);
+       if (ret)
+               dev_err(dev, "problem resetting device");
+
+       return ret;
+}
+
+/* Power down the device */
+int adis16251_stop_device(struct device *dev)
+{
+       int ret;
+       u16 val = ADIS16251_SLP_CNT_POWER_OFF;
+
+       ret = adis16251_spi_write_reg_16(dev, ADIS16251_SLP_CNT, val);
+       if (ret)
+               dev_err(dev, "problem with turning device off: SLP_CNT");
+
+       return ret;
+}
+
+static int adis16251_self_test(struct device *dev)
+{
+       int ret;
+
+       ret = adis16251_spi_write_reg_16(dev,
+                       ADIS16251_MSC_CTRL,
+                       ADIS16251_MSC_CTRL_INT_SELF_TEST);
+       if (ret) {
+               dev_err(dev, "problem starting self test");
+               goto err_ret;
+       }
+
+       adis16251_check_status(dev);
+
+err_ret:
+       return ret;
+}
+
+int adis16251_check_status(struct device *dev)
+{
+       u16 status;
+       int ret;
+
+       ret = adis16251_spi_read_reg_16(dev, ADIS16251_DIAG_STAT, &status);
+
+       if (ret < 0) {
+               dev_err(dev, "Reading status failed\n");
+               goto error_ret;
+       }
+
+       if (!(status & ADIS16251_DIAG_STAT_ERR_MASK)) {
+               ret = 0;
+               goto error_ret;
+       }
+
+       ret = -EFAULT;
+
+       if (status & ADIS16251_DIAG_STAT_ALARM2)
+               dev_err(dev, "Alarm 2 active\n");
+       if (status & ADIS16251_DIAG_STAT_ALARM1)
+               dev_err(dev, "Alarm 1 active\n");
+       if (status & ADIS16251_DIAG_STAT_SELF_TEST)
+               dev_err(dev, "Self test error\n");
+       if (status & ADIS16251_DIAG_STAT_OVERFLOW)
+               dev_err(dev, "Sensor overrange\n");
+       if (status & ADIS16251_DIAG_STAT_SPI_FAIL)
+               dev_err(dev, "SPI failure\n");
+       if (status & ADIS16251_DIAG_STAT_FLASH_UPT)
+               dev_err(dev, "Flash update failed\n");
+       if (status & ADIS16251_DIAG_STAT_POWER_HIGH)
+               dev_err(dev, "Power supply above 5.25V\n");
+       if (status & ADIS16251_DIAG_STAT_POWER_LOW)
+               dev_err(dev, "Power supply below 4.75V\n");
+
+error_ret:
+       return ret;
+}
+
+static int adis16251_initial_setup(struct adis16251_state *st)
+{
+       int ret;
+       u16 smp_prd;
+       struct device *dev = &st->indio_dev->dev;
+
+       /* use low spi speed for init */
+       st->us->max_speed_hz = ADIS16251_SPI_SLOW;
+       st->us->mode = SPI_MODE_3;
+       spi_setup(st->us);
+
+       /* Disable IRQ */
+       ret = adis16251_set_irq(dev, false);
+       if (ret) {
+               dev_err(dev, "disable irq failed");
+               goto err_ret;
+       }
+
+       /* Do self test */
+
+       /* Read status register to check the result */
+       ret = adis16251_check_status(dev);
+       if (ret) {
+               adis16251_reset(dev);
+               dev_err(dev, "device not playing ball -> reset");
+               msleep(ADIS16251_STARTUP_DELAY);
+               ret = adis16251_check_status(dev);
+               if (ret) {
+                       dev_err(dev, "giving up");
+                       goto err_ret;
+               }
+       }
+
+       printk(KERN_INFO DRIVER_NAME ": at CS%d (irq %d)\n",
+                       st->us->chip_select, st->us->irq);
+
+       /* use high spi speed if possible */
+       ret = adis16251_spi_read_reg_16(dev, ADIS16251_SMPL_PRD, &smp_prd);
+       if (!ret && (smp_prd & ADIS16251_SMPL_PRD_DIV_MASK) < 0x0A) {
+               st->us->max_speed_hz = ADIS16251_SPI_SLOW;
+               spi_setup(st->us);
+       }
+
+err_ret:
+       return ret;
+}
+
+static IIO_DEV_ATTR_IN_NAMED_RAW(0, supply, adis16251_read_12bit_signed,
+               ADIS16251_SUPPLY_OUT);
+static IIO_CONST_ATTR(in0_supply_scale, "0.0018315");
+
+static IIO_DEV_ATTR_GYRO(adis16251_read_14bit_signed,
+               ADIS16251_GYRO_OUT);
+static IIO_DEV_ATTR_GYRO_SCALE(S_IWUSR | S_IRUGO,
+               adis16251_read_12bit_signed,
+               adis16251_write_16bit,
+               ADIS16251_GYRO_SCALE);
+static IIO_DEV_ATTR_GYRO_OFFSET(S_IWUSR | S_IRUGO,
+               adis16251_read_12bit_signed,
+               adis16251_write_16bit,
+               ADIS16251_GYRO_OFF);
+
+static IIO_DEV_ATTR_TEMP_RAW(adis16251_read_12bit_signed);
+static IIO_CONST_ATTR(temp_offset, "25 K");
+static IIO_CONST_ATTR(temp_scale, "0.1453 K");
+
+static IIO_DEV_ATTR_IN_NAMED_RAW(1, aux, adis16251_read_12bit_unsigned,
+               ADIS16251_AUX_ADC);
+static IIO_CONST_ATTR(in1_aux_scale, "0.0006105");
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+               adis16251_read_frequency,
+               adis16251_write_frequency);
+static IIO_DEV_ATTR_ANGL(adis16251_read_14bit_signed,
+               ADIS16251_ANGL_OUT);
+
+static IIO_DEV_ATTR_RESET(adis16251_write_reset);
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("0.129 ~ 256");
+
+static IIO_CONST_ATTR(name, "adis16251");
+
+static struct attribute *adis16251_event_attributes[] = {
+       NULL
+};
+
+static struct attribute_group adis16251_event_attribute_group = {
+       .attrs = adis16251_event_attributes,
+};
+
+static struct attribute *adis16251_attributes[] = {
+       &iio_dev_attr_in0_supply_raw.dev_attr.attr,
+       &iio_const_attr_in0_supply_scale.dev_attr.attr,
+       &iio_dev_attr_gyro_raw.dev_attr.attr,
+       &iio_dev_attr_gyro_scale.dev_attr.attr,
+       &iio_dev_attr_gyro_offset.dev_attr.attr,
+       &iio_dev_attr_angl_raw.dev_attr.attr,
+       &iio_dev_attr_temp_raw.dev_attr.attr,
+       &iio_const_attr_temp_offset.dev_attr.attr,
+       &iio_const_attr_temp_scale.dev_attr.attr,
+       &iio_dev_attr_in1_aux_raw.dev_attr.attr,
+       &iio_const_attr_in1_aux_scale.dev_attr.attr,
+       &iio_dev_attr_sampling_frequency.dev_attr.attr,
+       &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+       &iio_dev_attr_reset.dev_attr.attr,
+       &iio_const_attr_name.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group adis16251_attribute_group = {
+       .attrs = adis16251_attributes,
+};
+
+static int __devinit adis16251_probe(struct spi_device *spi)
+{
+       int ret, regdone = 0;
+       struct adis16251_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+       if (!st) {
+               ret =  -ENOMEM;
+               goto error_ret;
+       }
+       /* this is only used for removal purposes */
+       spi_set_drvdata(spi, st);
+
+       /* Allocate the comms buffers */
+       st->rx = kzalloc(sizeof(*st->rx)*ADIS16251_MAX_RX, GFP_KERNEL);
+       if (st->rx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->tx = kzalloc(sizeof(*st->tx)*ADIS16251_MAX_TX, GFP_KERNEL);
+       if (st->tx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_rx;
+       }
+       st->us = spi;
+       mutex_init(&st->buf_lock);
+       /* setup the industrialio driver allocated elements */
+       st->indio_dev = iio_allocate_device();
+       if (st->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_tx;
+       }
+
+       st->indio_dev->dev.parent = &spi->dev;
+       st->indio_dev->num_interrupt_lines = 1;
+       st->indio_dev->event_attrs = &adis16251_event_attribute_group;
+       st->indio_dev->attrs = &adis16251_attribute_group;
+       st->indio_dev->dev_data = (void *)(st);
+       st->indio_dev->driver_module = THIS_MODULE;
+       st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = adis16251_configure_ring(st->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       ret = iio_device_register(st->indio_dev);
+       if (ret)
+               goto error_unreg_ring_funcs;
+       regdone = 1;
+
+       ret = adis16251_initialize_ring(st->indio_dev->ring);
+       if (ret) {
+               printk(KERN_ERR "failed to initialize the ring\n");
+               goto error_unreg_ring_funcs;
+       }
+
+       if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) {
+               ret = iio_register_interrupt_line(spi->irq,
+                               st->indio_dev,
+                               0,
+                               IRQF_TRIGGER_RISING,
+                               "adis16251");
+               if (ret)
+                       goto error_uninitialize_ring;
+
+               ret = adis16251_probe_trigger(st->indio_dev);
+               if (ret)
+                       goto error_unregister_line;
+       }
+
+       /* Get the device into a sane initial state */
+       ret = adis16251_initial_setup(st);
+       if (ret)
+               goto error_remove_trigger;
+       return 0;
+
+error_remove_trigger:
+       if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+               adis16251_remove_trigger(st->indio_dev);
+error_unregister_line:
+       if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+               iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+       adis16251_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+       adis16251_unconfigure_ring(st->indio_dev);
+error_free_dev:
+       if (regdone)
+               iio_device_unregister(st->indio_dev);
+       else
+               iio_free_device(st->indio_dev);
+error_free_tx:
+       kfree(st->tx);
+error_free_rx:
+       kfree(st->rx);
+error_free_st:
+       kfree(st);
+error_ret:
+       return ret;
+}
+
+/* fixme, confirm ordering in this function */
+static int adis16251_remove(struct spi_device *spi)
+{
+       int ret;
+       struct adis16251_state *st = spi_get_drvdata(spi);
+       struct iio_dev *indio_dev = st->indio_dev;
+
+       ret = adis16251_stop_device(&(indio_dev->dev));
+       if (ret)
+               goto err_ret;
+
+       flush_scheduled_work();
+
+       adis16251_remove_trigger(indio_dev);
+       if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
+               iio_unregister_interrupt_line(indio_dev, 0);
+
+       adis16251_uninitialize_ring(indio_dev->ring);
+       adis16251_unconfigure_ring(indio_dev);
+       iio_device_unregister(indio_dev);
+       kfree(st->tx);
+       kfree(st->rx);
+       kfree(st);
+
+       return 0;
+
+err_ret:
+       return ret;
+}
+
+static struct spi_driver adis16251_driver = {
+       .driver = {
+               .name = "adis16251",
+               .owner = THIS_MODULE,
+       },
+       .probe = adis16251_probe,
+       .remove = __devexit_p(adis16251_remove),
+};
+
+static __init int adis16251_init(void)
+{
+       return spi_register_driver(&adis16251_driver);
+}
+module_init(adis16251_init);
+
+static __exit void adis16251_exit(void)
+{
+       spi_unregister_driver(&adis16251_driver);
+}
+module_exit(adis16251_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADIS16251 Digital Gyroscope Sensor SPI driver");
+MODULE_LICENSE("GPL v2");
index 7d7716e5857c67177a9ace99f70a6c9beac3b9f7..8190c0fe0bea7da41e2899e20b0ed20e1b3497bb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * ADIS16260 Programmable Digital Gyroscope Sensor Driver
+ * ADIS16260/ADIS16265 Programmable Digital Gyroscope Sensor Driver
  *
  * Copyright 2010 Analog Devices Inc.
  *
index 97c1ec8594ced2f14b3d50e6b200cce47d50602a..cf7176bc766bce19a2b73d584651c542ecd8ad35 100644 (file)
@@ -570,6 +570,7 @@ static struct attribute *adis16350_attributes[] = {
        &iio_dev_attr_temp_y_raw.dev_attr.attr,
        &iio_dev_attr_temp_z_raw.dev_attr.attr,
        &iio_const_attr_temp_scale.dev_attr.attr,
+       &iio_const_attr_temp_offset.dev_attr.attr,
        &iio_dev_attr_in1_raw.dev_attr.attr,
        &iio_const_attr_in1_scale.dev_attr.attr,
        &iio_dev_attr_sampling_frequency.dev_attr.attr,
diff --git a/drivers/staging/iio/meter/Kconfig b/drivers/staging/iio/meter/Kconfig
new file mode 100644 (file)
index 0000000..12e36e4
--- /dev/null
@@ -0,0 +1,61 @@
+#
+# IIO meter drivers configuration
+#
+comment "Active energy metering IC"
+
+config ADE7753
+       tristate "Analog Devices ADE7753/6 Single-Phase Multifunction Metering IC Driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices ADE7753 Single-Phase Multifunction
+         Metering IC with di/dt Sensor Interface.
+
+config ADE7754
+       tristate "Analog Devices ADE7754 Polyphase Multifunction Energy Metering IC Driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices ADE7754 Polyphase
+         Multifunction Energy Metering IC Driver.
+
+config ADE7758
+       tristate "Analog Devices ADE7758 Poly Phase Multifunction Energy Metering IC Driver"
+       depends on SPI
+       select IIO_TRIGGER if IIO_RING_BUFFER
+       select IIO_SW_RING if IIO_RING_BUFFER
+       help
+         Say yes here to build support for Analog Devices ADE7758 Polyphase
+         Multifunction Energy Metering IC with Per Phase Information Driver.
+
+config ADE7759
+       tristate "Analog Devices ADE7759 Active Energy Metering IC Driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices ADE7758 Active Energy
+         Metering IC with di/dt Sensor Interface.
+
+config ADE7854
+       tristate "Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver"
+       depends on SPI || I2C
+       help
+         Say yes here to build support for Analog Devices ADE7854/58/68/78 Polyphase
+         Multifunction Energy Metering IC Driver.
+
+config ADE7854_I2C
+       tristate "support I2C bus connection"
+       depends on ADE7854 && I2C
+       default y
+       help
+         Say Y here if you have ADE7854/58/68/78 hooked to an I2C bus.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ade7854-i2c.
+
+config ADE7854_SPI
+       tristate "support SPI bus connection"
+       depends on ADE7854 && SPI
+       default y
+       help
+         Say Y here if you have ADE7854/58/68/78 hooked to a SPI bus.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ade7854-spi.
diff --git a/drivers/staging/iio/meter/Makefile b/drivers/staging/iio/meter/Makefile
new file mode 100644 (file)
index 0000000..0cc7d51
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# Makefile for metering ic drivers
+#
+
+obj-$(CONFIG_ADE7753) += ade7753.o
+obj-$(CONFIG_ADE7754) += ade7754.o
+
+ade7758-y             := ade7758_core.o
+ade7758-$(CONFIG_IIO_RING_BUFFER) += ade7758_ring.o ade7758_trigger.o
+obj-$(CONFIG_ADE7758) += ade7758.o
+
+obj-$(CONFIG_ADE7759) += ade7759.o
+obj-$(CONFIG_ADE7854) += ade7854.o
+obj-$(CONFIG_ADE7854_I2C) += ade7854-i2c.o
+obj-$(CONFIG_ADE7854_SPI) += ade7854-spi.o
diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c
new file mode 100644 (file)
index 0000000..e72afbd
--- /dev/null
@@ -0,0 +1,730 @@
+/*
+ * ADE7753 Single-Phase Multifunction Metering IC with di/dt Sensor Interface Driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "meter.h"
+#include "ade7753.h"
+
+int ade7753_spi_write_reg_8(struct device *dev,
+               u8 reg_address,
+               u8 val)
+{
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7753_state *st = iio_dev_get_devdata(indio_dev);
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7753_WRITE_REG(reg_address);
+       st->tx[1] = val;
+
+       ret = spi_write(st->us, st->tx, 2);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static int ade7753_spi_write_reg_16(struct device *dev,
+               u8 reg_address,
+               u16 value)
+{
+       int ret;
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7753_state *st = iio_dev_get_devdata(indio_dev);
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 3,
+               }
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7753_WRITE_REG(reg_address);
+       st->tx[1] = (value >> 8) & 0xFF;
+       st->tx[2] = value & 0xFF;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->us, &msg);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static int ade7753_spi_read_reg_8(struct device *dev,
+               u8 reg_address,
+               u8 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7753_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .rx_buf = st->rx,
+                       .bits_per_word = 8,
+                       .len = 2,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7753_READ_REG(reg_address);
+       st->tx[1] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->us, &msg);
+       if (ret) {
+               dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X",
+                               reg_address);
+               goto error_ret;
+       }
+       *val = st->rx[1];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static int ade7753_spi_read_reg_16(struct device *dev,
+               u8 reg_address,
+               u16 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7753_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .rx_buf = st->rx,
+                       .bits_per_word = 8,
+                       .len = 3,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7753_READ_REG(reg_address);
+       st->tx[1] = 0;
+       st->tx[2] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->us, &msg);
+       if (ret) {
+               dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
+                               reg_address);
+               goto error_ret;
+       }
+       *val = (st->rx[1] << 8) | st->rx[2];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static int ade7753_spi_read_reg_24(struct device *dev,
+               u8 reg_address,
+               u32 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7753_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .rx_buf = st->rx,
+                       .bits_per_word = 8,
+                       .len = 4,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7753_READ_REG(reg_address);
+       st->tx[1] = 0;
+       st->tx[2] = 0;
+       st->tx[3] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->us, &msg);
+       if (ret) {
+               dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X",
+                               reg_address);
+               goto error_ret;
+       }
+       *val = (st->rx[1] << 16) | (st->rx[2] << 8) | st->rx[3];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static ssize_t ade7753_read_8bit(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u8 val = 0;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = ade7753_spi_read_reg_8(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7753_read_16bit(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u16 val = 0;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = ade7753_spi_read_reg_16(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7753_read_24bit(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u32 val = 0;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = ade7753_spi_read_reg_24(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%u\n", val & 0xFFFFFF);
+}
+
+static ssize_t ade7753_write_8bit(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       int ret;
+       long val;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               goto error_ret;
+       ret = ade7753_spi_write_reg_8(dev, this_attr->address, val);
+
+error_ret:
+       return ret ? ret : len;
+}
+
+static ssize_t ade7753_write_16bit(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       int ret;
+       long val;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               goto error_ret;
+       ret = ade7753_spi_write_reg_16(dev, this_attr->address, val);
+
+error_ret:
+       return ret ? ret : len;
+}
+
+static int ade7753_reset(struct device *dev)
+{
+       int ret;
+       u16 val;
+       ade7753_spi_read_reg_16(dev,
+                       ADE7753_MODE,
+                       &val);
+       val |= 1 << 6; /* Software Chip Reset */
+       ret = ade7753_spi_write_reg_16(dev,
+                       ADE7753_MODE,
+                       val);
+
+       return ret;
+}
+
+static ssize_t ade7753_write_reset(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf, size_t len)
+{
+       if (len < 1)
+               return -1;
+       switch (buf[0]) {
+       case '1':
+       case 'y':
+       case 'Y':
+               return ade7753_reset(dev);
+       }
+       return -1;
+}
+
+static IIO_DEV_ATTR_AENERGY(ade7753_read_24bit, ADE7753_AENERGY);
+static IIO_DEV_ATTR_LAENERGY(ade7753_read_24bit, ADE7753_LAENERGY);
+static IIO_DEV_ATTR_VAENERGY(ade7753_read_24bit, ADE7753_VAENERGY);
+static IIO_DEV_ATTR_LVAENERGY(ade7753_read_24bit, ADE7753_LVAENERGY);
+static IIO_DEV_ATTR_CFDEN(S_IWUSR | S_IRUGO,
+               ade7753_read_16bit,
+               ade7753_write_16bit,
+               ADE7753_CFDEN);
+static IIO_DEV_ATTR_CFNUM(S_IWUSR | S_IRUGO,
+               ade7753_read_8bit,
+               ade7753_write_8bit,
+               ADE7753_CFNUM);
+static IIO_DEV_ATTR_CHKSUM(ade7753_read_8bit, ADE7753_CHKSUM);
+static IIO_DEV_ATTR_PHCAL(S_IWUSR | S_IRUGO,
+               ade7753_read_16bit,
+               ade7753_write_16bit,
+               ADE7753_PHCAL);
+static IIO_DEV_ATTR_APOS(S_IWUSR | S_IRUGO,
+               ade7753_read_16bit,
+               ade7753_write_16bit,
+               ADE7753_APOS);
+static IIO_DEV_ATTR_SAGCYC(S_IWUSR | S_IRUGO,
+               ade7753_read_8bit,
+               ade7753_write_8bit,
+               ADE7753_SAGCYC);
+static IIO_DEV_ATTR_SAGLVL(S_IWUSR | S_IRUGO,
+               ade7753_read_8bit,
+               ade7753_write_8bit,
+               ADE7753_SAGLVL);
+static IIO_DEV_ATTR_LINECYC(S_IWUSR | S_IRUGO,
+               ade7753_read_8bit,
+               ade7753_write_8bit,
+               ADE7753_LINECYC);
+static IIO_DEV_ATTR_WDIV(S_IWUSR | S_IRUGO,
+               ade7753_read_8bit,
+               ade7753_write_8bit,
+               ADE7753_WDIV);
+static IIO_DEV_ATTR_IRMS(S_IWUSR | S_IRUGO,
+               ade7753_read_24bit,
+               NULL,
+               ADE7753_IRMS);
+static IIO_DEV_ATTR_VRMS(S_IRUGO,
+               ade7753_read_24bit,
+               NULL,
+               ADE7753_VRMS);
+static IIO_DEV_ATTR_IRMSOS(S_IWUSR | S_IRUGO,
+               ade7753_read_16bit,
+               ade7753_write_16bit,
+               ADE7753_IRMSOS);
+static IIO_DEV_ATTR_VRMSOS(S_IWUSR | S_IRUGO,
+               ade7753_read_16bit,
+               ade7753_write_16bit,
+               ADE7753_VRMSOS);
+static IIO_DEV_ATTR_WGAIN(S_IWUSR | S_IRUGO,
+               ade7753_read_16bit,
+               ade7753_write_16bit,
+               ADE7753_WGAIN);
+static IIO_DEV_ATTR_VAGAIN(S_IWUSR | S_IRUGO,
+               ade7753_read_16bit,
+               ade7753_write_16bit,
+               ADE7753_VAGAIN);
+static IIO_DEV_ATTR_PGA_GAIN(S_IWUSR | S_IRUGO,
+               ade7753_read_16bit,
+               ade7753_write_16bit,
+               ADE7753_GAIN);
+static IIO_DEV_ATTR_IPKLVL(S_IWUSR | S_IRUGO,
+               ade7753_read_8bit,
+               ade7753_write_8bit,
+               ADE7753_IPKLVL);
+static IIO_DEV_ATTR_VPKLVL(S_IWUSR | S_IRUGO,
+               ade7753_read_8bit,
+               ade7753_write_8bit,
+               ADE7753_VPKLVL);
+static IIO_DEV_ATTR_IPEAK(S_IRUGO,
+               ade7753_read_24bit,
+               NULL,
+               ADE7753_IPEAK);
+static IIO_DEV_ATTR_VPEAK(S_IRUGO,
+               ade7753_read_24bit,
+               NULL,
+               ADE7753_VPEAK);
+static IIO_DEV_ATTR_VPERIOD(S_IRUGO,
+               ade7753_read_16bit,
+               NULL,
+               ADE7753_PERIOD);
+static IIO_DEV_ATTR_CH_OFF(1, S_IWUSR | S_IRUGO,
+               ade7753_read_8bit,
+               ade7753_write_8bit,
+               ADE7753_CH1OS);
+static IIO_DEV_ATTR_CH_OFF(2, S_IWUSR | S_IRUGO,
+               ade7753_read_8bit,
+               ade7753_write_8bit,
+               ADE7753_CH2OS);
+
+static int ade7753_set_irq(struct device *dev, bool enable)
+{
+       int ret;
+       u8 irqen;
+       ret = ade7753_spi_read_reg_8(dev, ADE7753_IRQEN, &irqen);
+       if (ret)
+               goto error_ret;
+
+       if (enable)
+               irqen |= 1 << 3; /* Enables an interrupt when a data is
+                                   present in the waveform register */
+       else
+               irqen &= ~(1 << 3);
+
+       ret = ade7753_spi_write_reg_8(dev, ADE7753_IRQEN, irqen);
+       if (ret)
+               goto error_ret;
+
+error_ret:
+       return ret;
+}
+
+/* Power down the device */
+int ade7753_stop_device(struct device *dev)
+{
+       int ret;
+       u16 val;
+       ade7753_spi_read_reg_16(dev,
+                       ADE7753_MODE,
+                       &val);
+       val |= 1 << 4;  /* AD converters can be turned off */
+       ret = ade7753_spi_write_reg_16(dev,
+                       ADE7753_MODE,
+                       val);
+
+       return ret;
+}
+
+static int ade7753_initial_setup(struct ade7753_state *st)
+{
+       int ret;
+       struct device *dev = &st->indio_dev->dev;
+
+       /* use low spi speed for init */
+       st->us->mode = SPI_MODE_3;
+       spi_setup(st->us);
+
+       /* Disable IRQ */
+       ret = ade7753_set_irq(dev, false);
+       if (ret) {
+               dev_err(dev, "disable irq failed");
+               goto err_ret;
+       }
+
+       ade7753_reset(dev);
+       msleep(ADE7753_STARTUP_DELAY);
+
+err_ret:
+       return ret;
+}
+
+static ssize_t ade7753_read_frequency(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret, len = 0;
+       u8 t;
+       int sps;
+       ret = ade7753_spi_read_reg_8(dev,
+                       ADE7753_MODE,
+                       &t);
+       if (ret)
+               return ret;
+
+       t = (t >> 11) & 0x3;
+       sps = 27900 / (1 + t);
+
+       len = sprintf(buf, "%d SPS\n", sps);
+       return len;
+}
+
+static ssize_t ade7753_write_frequency(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7753_state *st = iio_dev_get_devdata(indio_dev);
+       unsigned long val;
+       int ret;
+       u16 reg, t;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               return ret;
+
+       mutex_lock(&indio_dev->mlock);
+
+       t = (27900 / val);
+       if (t > 0)
+               t--;
+
+       if (t > 1)
+               st->us->max_speed_hz = ADE7753_SPI_SLOW;
+       else
+               st->us->max_speed_hz = ADE7753_SPI_FAST;
+
+       ret = ade7753_spi_read_reg_16(dev,
+                       ADE7753_MODE,
+                       &reg);
+       if (ret)
+               goto out;
+
+       reg &= ~(3 << 11);
+       reg |= t << 11;
+
+       ret = ade7753_spi_write_reg_16(dev,
+                       ADE7753_MODE,
+                       reg);
+
+out:
+       mutex_unlock(&indio_dev->mlock);
+
+       return ret ? ret : len;
+}
+static IIO_DEV_ATTR_TEMP_RAW(ade7753_read_8bit);
+static IIO_CONST_ATTR(temp_offset, "-25 C");
+static IIO_CONST_ATTR(temp_scale, "0.67 C");
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+               ade7753_read_frequency,
+               ade7753_write_frequency);
+
+static IIO_DEV_ATTR_RESET(ade7753_write_reset);
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("27900 14000 7000 3500");
+
+static IIO_CONST_ATTR(name, "ade7753");
+
+static struct attribute *ade7753_event_attributes[] = {
+       NULL
+};
+
+static struct attribute_group ade7753_event_attribute_group = {
+       .attrs = ade7753_event_attributes,
+};
+
+static struct attribute *ade7753_attributes[] = {
+       &iio_dev_attr_temp_raw.dev_attr.attr,
+       &iio_const_attr_temp_offset.dev_attr.attr,
+       &iio_const_attr_temp_scale.dev_attr.attr,
+       &iio_dev_attr_sampling_frequency.dev_attr.attr,
+       &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+       &iio_dev_attr_reset.dev_attr.attr,
+       &iio_const_attr_name.dev_attr.attr,
+       &iio_dev_attr_phcal.dev_attr.attr,
+       &iio_dev_attr_cfden.dev_attr.attr,
+       &iio_dev_attr_aenergy.dev_attr.attr,
+       &iio_dev_attr_laenergy.dev_attr.attr,
+       &iio_dev_attr_vaenergy.dev_attr.attr,
+       &iio_dev_attr_lvaenergy.dev_attr.attr,
+       &iio_dev_attr_cfnum.dev_attr.attr,
+       &iio_dev_attr_apos.dev_attr.attr,
+       &iio_dev_attr_sagcyc.dev_attr.attr,
+       &iio_dev_attr_saglvl.dev_attr.attr,
+       &iio_dev_attr_linecyc.dev_attr.attr,
+       &iio_dev_attr_chksum.dev_attr.attr,
+       &iio_dev_attr_pga_gain.dev_attr.attr,
+       &iio_dev_attr_wgain.dev_attr.attr,
+       &iio_dev_attr_choff_1.dev_attr.attr,
+       &iio_dev_attr_choff_2.dev_attr.attr,
+       &iio_dev_attr_wdiv.dev_attr.attr,
+       &iio_dev_attr_irms.dev_attr.attr,
+       &iio_dev_attr_vrms.dev_attr.attr,
+       &iio_dev_attr_irmsos.dev_attr.attr,
+       &iio_dev_attr_vrmsos.dev_attr.attr,
+       &iio_dev_attr_vagain.dev_attr.attr,
+       &iio_dev_attr_ipklvl.dev_attr.attr,
+       &iio_dev_attr_vpklvl.dev_attr.attr,
+       &iio_dev_attr_ipeak.dev_attr.attr,
+       &iio_dev_attr_vpeak.dev_attr.attr,
+       &iio_dev_attr_vperiod.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ade7753_attribute_group = {
+       .attrs = ade7753_attributes,
+};
+
+static int __devinit ade7753_probe(struct spi_device *spi)
+{
+       int ret, regdone = 0;
+       struct ade7753_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+       if (!st) {
+               ret =  -ENOMEM;
+               goto error_ret;
+       }
+       /* this is only used for removal purposes */
+       spi_set_drvdata(spi, st);
+
+       /* Allocate the comms buffers */
+       st->rx = kzalloc(sizeof(*st->rx)*ADE7753_MAX_RX, GFP_KERNEL);
+       if (st->rx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->tx = kzalloc(sizeof(*st->tx)*ADE7753_MAX_TX, GFP_KERNEL);
+       if (st->tx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_rx;
+       }
+       st->us = spi;
+       mutex_init(&st->buf_lock);
+       /* setup the industrialio driver allocated elements */
+       st->indio_dev = iio_allocate_device();
+       if (st->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_tx;
+       }
+
+       st->indio_dev->dev.parent = &spi->dev;
+       st->indio_dev->num_interrupt_lines = 1;
+       st->indio_dev->event_attrs = &ade7753_event_attribute_group;
+       st->indio_dev->attrs = &ade7753_attribute_group;
+       st->indio_dev->dev_data = (void *)(st);
+       st->indio_dev->driver_module = THIS_MODULE;
+       st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = ade7753_configure_ring(st->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       ret = iio_device_register(st->indio_dev);
+       if (ret)
+               goto error_unreg_ring_funcs;
+       regdone = 1;
+
+       ret = ade7753_initialize_ring(st->indio_dev->ring);
+       if (ret) {
+               printk(KERN_ERR "failed to initialize the ring\n");
+               goto error_unreg_ring_funcs;
+       }
+
+       if (spi->irq) {
+               ret = iio_register_interrupt_line(spi->irq,
+                               st->indio_dev,
+                               0,
+                               IRQF_TRIGGER_FALLING,
+                               "ade7753");
+               if (ret)
+                       goto error_uninitialize_ring;
+
+               ret = ade7753_probe_trigger(st->indio_dev);
+               if (ret)
+                       goto error_unregister_line;
+       }
+
+       /* Get the device into a sane initial state */
+       ret = ade7753_initial_setup(st);
+       if (ret)
+               goto error_remove_trigger;
+       return 0;
+
+error_remove_trigger:
+       if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+               ade7753_remove_trigger(st->indio_dev);
+error_unregister_line:
+       if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+               iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+       ade7753_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+       ade7753_unconfigure_ring(st->indio_dev);
+error_free_dev:
+       if (regdone)
+               iio_device_unregister(st->indio_dev);
+       else
+               iio_free_device(st->indio_dev);
+error_free_tx:
+       kfree(st->tx);
+error_free_rx:
+       kfree(st->rx);
+error_free_st:
+       kfree(st);
+error_ret:
+       return ret;
+}
+
+/* fixme, confirm ordering in this function */
+static int ade7753_remove(struct spi_device *spi)
+{
+       int ret;
+       struct ade7753_state *st = spi_get_drvdata(spi);
+       struct iio_dev *indio_dev = st->indio_dev;
+
+       ret = ade7753_stop_device(&(indio_dev->dev));
+       if (ret)
+               goto err_ret;
+
+       flush_scheduled_work();
+
+       ade7753_remove_trigger(indio_dev);
+       if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
+               iio_unregister_interrupt_line(indio_dev, 0);
+
+       ade7753_uninitialize_ring(indio_dev->ring);
+       ade7753_unconfigure_ring(indio_dev);
+       iio_device_unregister(indio_dev);
+       kfree(st->tx);
+       kfree(st->rx);
+       kfree(st);
+
+       return 0;
+
+err_ret:
+       return ret;
+}
+
+static struct spi_driver ade7753_driver = {
+       .driver = {
+               .name = "ade7753",
+               .owner = THIS_MODULE,
+       },
+       .probe = ade7753_probe,
+       .remove = __devexit_p(ade7753_remove),
+};
+
+static __init int ade7753_init(void)
+{
+       return spi_register_driver(&ade7753_driver);
+}
+module_init(ade7753_init);
+
+static __exit void ade7753_exit(void)
+{
+       spi_unregister_driver(&ade7753_driver);
+}
+module_exit(ade7753_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADE7753/6 Single-Phase Multifunction Metering IC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/meter/ade7753.h b/drivers/staging/iio/meter/ade7753.h
new file mode 100644 (file)
index 0000000..a3722b8
--- /dev/null
@@ -0,0 +1,140 @@
+#ifndef _ADE7753_H
+#define _ADE7753_H
+
+#define ADE7753_WAVEFORM   0x01
+#define ADE7753_AENERGY    0x02
+#define ADE7753_RAENERGY   0x03
+#define ADE7753_LAENERGY   0x04
+#define ADE7753_VAENERGY   0x05
+#define ADE7753_RVAENERGY  0x06
+#define ADE7753_LVAENERGY  0x07
+#define ADE7753_LVARENERGY 0x08
+#define ADE7753_MODE       0x09
+#define ADE7753_IRQEN      0x0A
+#define ADE7753_STATUS     0x0B
+#define ADE7753_RSTSTATUS  0x0C
+#define ADE7753_CH1OS      0x0D
+#define ADE7753_CH2OS      0x0E
+#define ADE7753_GAIN       0x0F
+#define ADE7753_PHCAL      0x10
+#define ADE7753_APOS       0x11
+#define ADE7753_WGAIN      0x12
+#define ADE7753_WDIV       0x13
+#define ADE7753_CFNUM      0x14
+#define ADE7753_CFDEN      0x15
+#define ADE7753_IRMS       0x16
+#define ADE7753_VRMS       0x17
+#define ADE7753_IRMSOS     0x18
+#define ADE7753_VRMSOS     0x19
+#define ADE7753_VAGAIN     0x1A
+#define ADE7753_VADIV      0x1B
+#define ADE7753_LINECYC    0x1C
+#define ADE7753_ZXTOUT     0x1D
+#define ADE7753_SAGCYC     0x1E
+#define ADE7753_SAGLVL     0x1F
+#define ADE7753_IPKLVL     0x20
+#define ADE7753_VPKLVL     0x21
+#define ADE7753_IPEAK      0x22
+#define ADE7753_RSTIPEAK   0x23
+#define ADE7753_VPEAK      0x24
+#define ADE7753_RSTVPEAK   0x25
+#define ADE7753_TEMP       0x26
+#define ADE7753_PERIOD     0x27
+#define ADE7753_TMODE      0x3D
+#define ADE7753_CHKSUM     0x3E
+#define ADE7753_DIEREV     0x3F
+
+#define ADE7753_READ_REG(a)    a
+#define ADE7753_WRITE_REG(a) ((a) | 0x80)
+
+#define ADE7753_MAX_TX    4
+#define ADE7753_MAX_RX    4
+#define ADE7753_STARTUP_DELAY 1
+
+#define ADE7753_SPI_SLOW       (u32)(300 * 1000)
+#define ADE7753_SPI_BURST      (u32)(1000 * 1000)
+#define ADE7753_SPI_FAST       (u32)(2000 * 1000)
+
+#define DRIVER_NAME            "ade7753"
+
+/**
+ * struct ade7753_state - device instance specific data
+ * @us:                        actual spi_device
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter:             used to check if new interrupt has been triggered
+ * @last_timestamp:    passing timestamp from th to bh of interrupt handler
+ * @indio_dev:         industrial I/O device structure
+ * @trig:              data ready trigger registered with iio
+ * @tx:                        transmit buffer
+ * @rx:                        recieve buffer
+ * @buf_lock:          mutex to protect tx and rx
+ **/
+struct ade7753_state {
+       struct spi_device               *us;
+       struct work_struct              work_trigger_to_ring;
+       s64                             last_timestamp;
+       struct iio_dev                  *indio_dev;
+       struct iio_trigger              *trig;
+       u8                              *tx;
+       u8                              *rx;
+       struct mutex                    buf_lock;
+};
+#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
+
+enum ade7753_scan {
+       ADE7753_SCAN_ACTIVE_POWER,
+       ADE7753_SCAN_CH1,
+       ADE7753_SCAN_CH2,
+};
+
+void ade7753_remove_trigger(struct iio_dev *indio_dev);
+int ade7753_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t ade7753_read_data_from_ring(struct device *dev,
+               struct device_attribute *attr,
+               char *buf);
+
+
+int ade7753_configure_ring(struct iio_dev *indio_dev);
+void ade7753_unconfigure_ring(struct iio_dev *indio_dev);
+
+int ade7753_initialize_ring(struct iio_ring_buffer *ring);
+void ade7753_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void ade7753_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7753_probe_trigger(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline ssize_t
+ade7753_read_data_from_ring(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return 0;
+}
+
+static int ade7753_configure_ring(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+static inline void ade7753_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7753_initialize_ring(struct iio_ring_buffer *ring)
+{
+       return 0;
+}
+static inline void ade7753_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+#endif /* CONFIG_IIO_RING_BUFFER */
+
+#endif
diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c
new file mode 100644 (file)
index 0000000..23dedfa
--- /dev/null
@@ -0,0 +1,756 @@
+/*
+ * ADE7754 Polyphase Multifunction Energy Metering IC Driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "meter.h"
+#include "ade7754.h"
+
+static int ade7754_spi_write_reg_8(struct device *dev,
+               u8 reg_address,
+               u8 val)
+{
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7754_state *st = iio_dev_get_devdata(indio_dev);
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7754_WRITE_REG(reg_address);
+       st->tx[1] = val;
+
+       ret = spi_write(st->us, st->tx, 2);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static int ade7754_spi_write_reg_16(struct device *dev,
+               u8 reg_address,
+               u16 value)
+{
+       int ret;
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7754_state *st = iio_dev_get_devdata(indio_dev);
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 3,
+               }
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7754_WRITE_REG(reg_address);
+       st->tx[1] = (value >> 8) & 0xFF;
+       st->tx[2] = value & 0xFF;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->us, &msg);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static int ade7754_spi_read_reg_8(struct device *dev,
+               u8 reg_address,
+               u8 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7754_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .rx_buf = st->rx,
+                       .bits_per_word = 8,
+                       .len = 2,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7754_READ_REG(reg_address);
+       st->tx[1] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->us, &msg);
+       if (ret) {
+               dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X",
+                               reg_address);
+               goto error_ret;
+       }
+       *val = st->rx[1];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static int ade7754_spi_read_reg_16(struct device *dev,
+               u8 reg_address,
+               u16 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7754_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .rx_buf = st->rx,
+                       .bits_per_word = 8,
+                       .len = 3,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7754_READ_REG(reg_address);
+       st->tx[1] = 0;
+       st->tx[2] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->us, &msg);
+       if (ret) {
+               dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
+                               reg_address);
+               goto error_ret;
+       }
+       *val = (st->rx[1] << 8) | st->rx[2];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static int ade7754_spi_read_reg_24(struct device *dev,
+               u8 reg_address,
+               u32 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7754_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .rx_buf = st->rx,
+                       .bits_per_word = 8,
+                       .len = 4,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7754_READ_REG(reg_address);
+       st->tx[1] = 0;
+       st->tx[2] = 0;
+       st->tx[3] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->us, &msg);
+       if (ret) {
+               dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X",
+                               reg_address);
+               goto error_ret;
+       }
+       *val = (st->rx[1] << 16) | (st->rx[2] << 8) | st->rx[3];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static ssize_t ade7754_read_8bit(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u8 val = 0;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = ade7754_spi_read_reg_8(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7754_read_16bit(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u16 val = 0;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = ade7754_spi_read_reg_16(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7754_read_24bit(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u32 val = 0;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = ade7754_spi_read_reg_24(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%u\n", val & 0xFFFFFF);
+}
+
+static ssize_t ade7754_write_8bit(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       int ret;
+       long val;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               goto error_ret;
+       ret = ade7754_spi_write_reg_8(dev, this_attr->address, val);
+
+error_ret:
+       return ret ? ret : len;
+}
+
+static ssize_t ade7754_write_16bit(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       int ret;
+       long val;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               goto error_ret;
+       ret = ade7754_spi_write_reg_16(dev, this_attr->address, val);
+
+error_ret:
+       return ret ? ret : len;
+}
+
+static int ade7754_reset(struct device *dev)
+{
+       int ret;
+       u8 val;
+       ade7754_spi_read_reg_8(dev,
+                       ADE7754_OPMODE,
+                       &val);
+       val |= 1 << 6; /* Software Chip Reset */
+       ret = ade7754_spi_write_reg_8(dev,
+                       ADE7754_OPMODE,
+                       val);
+
+       return ret;
+}
+
+
+static ssize_t ade7754_write_reset(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf, size_t len)
+{
+       if (len < 1)
+               return -1;
+       switch (buf[0]) {
+       case '1':
+       case 'y':
+       case 'Y':
+               return ade7754_reset(dev);
+       }
+       return -1;
+}
+
+static IIO_DEV_ATTR_AENERGY(ade7754_read_24bit, ADE7754_AENERGY);
+static IIO_DEV_ATTR_LAENERGY(ade7754_read_24bit, ADE7754_LAENERGY);
+static IIO_DEV_ATTR_VAENERGY(ade7754_read_24bit, ADE7754_VAENERGY);
+static IIO_DEV_ATTR_LVAENERGY(ade7754_read_24bit, ADE7754_LVAENERGY);
+static IIO_DEV_ATTR_VPEAK(S_IWUSR | S_IRUGO,
+               ade7754_read_8bit,
+               ade7754_write_8bit,
+               ADE7754_VPEAK);
+static IIO_DEV_ATTR_IPEAK(S_IWUSR | S_IRUGO,
+               ade7754_read_8bit,
+               ade7754_write_8bit,
+               ADE7754_VPEAK);
+static IIO_DEV_ATTR_APHCAL(S_IWUSR | S_IRUGO,
+               ade7754_read_8bit,
+               ade7754_write_8bit,
+               ADE7754_APHCAL);
+static IIO_DEV_ATTR_BPHCAL(S_IWUSR | S_IRUGO,
+               ade7754_read_8bit,
+               ade7754_write_8bit,
+               ADE7754_BPHCAL);
+static IIO_DEV_ATTR_CPHCAL(S_IWUSR | S_IRUGO,
+               ade7754_read_8bit,
+               ade7754_write_8bit,
+               ADE7754_CPHCAL);
+static IIO_DEV_ATTR_AAPOS(S_IWUSR | S_IRUGO,
+               ade7754_read_16bit,
+               ade7754_write_16bit,
+               ADE7754_AAPOS);
+static IIO_DEV_ATTR_BAPOS(S_IWUSR | S_IRUGO,
+               ade7754_read_16bit,
+               ade7754_write_16bit,
+               ADE7754_BAPOS);
+static IIO_DEV_ATTR_CAPOS(S_IWUSR | S_IRUGO,
+               ade7754_read_16bit,
+               ade7754_write_16bit,
+               ADE7754_CAPOS);
+static IIO_DEV_ATTR_WDIV(S_IWUSR | S_IRUGO,
+               ade7754_read_8bit,
+               ade7754_write_8bit,
+               ADE7754_WDIV);
+static IIO_DEV_ATTR_VADIV(S_IWUSR | S_IRUGO,
+               ade7754_read_8bit,
+               ade7754_write_8bit,
+               ADE7754_VADIV);
+static IIO_DEV_ATTR_CFNUM(S_IWUSR | S_IRUGO,
+               ade7754_read_16bit,
+               ade7754_write_16bit,
+               ADE7754_CFNUM);
+static IIO_DEV_ATTR_CFDEN(S_IWUSR | S_IRUGO,
+               ade7754_read_16bit,
+               ade7754_write_16bit,
+               ADE7754_CFDEN);
+static IIO_DEV_ATTR_ACTIVE_POWER_A_GAIN(S_IWUSR | S_IRUGO,
+               ade7754_read_16bit,
+               ade7754_write_16bit,
+               ADE7754_AAPGAIN);
+static IIO_DEV_ATTR_ACTIVE_POWER_B_GAIN(S_IWUSR | S_IRUGO,
+               ade7754_read_16bit,
+               ade7754_write_16bit,
+               ADE7754_BAPGAIN);
+static IIO_DEV_ATTR_ACTIVE_POWER_C_GAIN(S_IWUSR | S_IRUGO,
+               ade7754_read_16bit,
+               ade7754_write_16bit,
+               ADE7754_CAPGAIN);
+static IIO_DEV_ATTR_AIRMS(S_IRUGO,
+               ade7754_read_24bit,
+               NULL,
+               ADE7754_AIRMS);
+static IIO_DEV_ATTR_BIRMS(S_IRUGO,
+               ade7754_read_24bit,
+               NULL,
+               ADE7754_BIRMS);
+static IIO_DEV_ATTR_CIRMS(S_IRUGO,
+               ade7754_read_24bit,
+               NULL,
+               ADE7754_CIRMS);
+static IIO_DEV_ATTR_AVRMS(S_IRUGO,
+               ade7754_read_24bit,
+               NULL,
+               ADE7754_AVRMS);
+static IIO_DEV_ATTR_BVRMS(S_IRUGO,
+               ade7754_read_24bit,
+               NULL,
+               ADE7754_BVRMS);
+static IIO_DEV_ATTR_CVRMS(S_IRUGO,
+               ade7754_read_24bit,
+               NULL,
+               ADE7754_CVRMS);
+static IIO_DEV_ATTR_AIRMSOS(S_IRUGO,
+               ade7754_read_16bit,
+               ade7754_write_16bit,
+               ADE7754_AIRMSOS);
+static IIO_DEV_ATTR_BIRMSOS(S_IRUGO,
+               ade7754_read_16bit,
+               ade7754_write_16bit,
+               ADE7754_BIRMSOS);
+static IIO_DEV_ATTR_CIRMSOS(S_IRUGO,
+               ade7754_read_16bit,
+               ade7754_write_16bit,
+               ADE7754_CIRMSOS);
+static IIO_DEV_ATTR_AVRMSOS(S_IRUGO,
+               ade7754_read_16bit,
+               ade7754_write_16bit,
+               ADE7754_AVRMSOS);
+static IIO_DEV_ATTR_BVRMSOS(S_IRUGO,
+               ade7754_read_16bit,
+               ade7754_write_16bit,
+               ADE7754_BVRMSOS);
+static IIO_DEV_ATTR_CVRMSOS(S_IRUGO,
+               ade7754_read_16bit,
+               ade7754_write_16bit,
+               ADE7754_CVRMSOS);
+
+static int ade7754_set_irq(struct device *dev, bool enable)
+{
+       int ret;
+       u16 irqen;
+       ret = ade7754_spi_read_reg_16(dev, ADE7754_IRQEN, &irqen);
+       if (ret)
+               goto error_ret;
+
+       if (enable)
+               irqen |= 1 << 14; /* Enables an interrupt when a data is
+                                    present in the waveform register */
+       else
+               irqen &= ~(1 << 14);
+
+       ret = ade7754_spi_write_reg_16(dev, ADE7754_IRQEN, irqen);
+       if (ret)
+               goto error_ret;
+
+error_ret:
+       return ret;
+}
+
+/* Power down the device */
+static int ade7754_stop_device(struct device *dev)
+{
+       int ret;
+       u8 val;
+       ade7754_spi_read_reg_8(dev,
+                       ADE7754_OPMODE,
+                       &val);
+       val |= 7 << 3;  /* ADE7754 powered down */
+       ret = ade7754_spi_write_reg_8(dev,
+                       ADE7754_OPMODE,
+                       val);
+
+       return ret;
+}
+
+static int ade7754_initial_setup(struct ade7754_state *st)
+{
+       int ret;
+       struct device *dev = &st->indio_dev->dev;
+
+       /* use low spi speed for init */
+       st->us->mode = SPI_MODE_3;
+       spi_setup(st->us);
+
+       /* Disable IRQ */
+       ret = ade7754_set_irq(dev, false);
+       if (ret) {
+               dev_err(dev, "disable irq failed");
+               goto err_ret;
+       }
+
+       ade7754_reset(dev);
+       msleep(ADE7754_STARTUP_DELAY);
+
+err_ret:
+       return ret;
+}
+
+static ssize_t ade7754_read_frequency(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret, len = 0;
+       u8 t;
+       int sps;
+       ret = ade7754_spi_read_reg_8(dev,
+                       ADE7754_WAVMODE,
+                       &t);
+       if (ret)
+               return ret;
+
+       t = (t >> 3) & 0x3;
+       sps = 26000 / (1 + t);
+
+       len = sprintf(buf, "%d SPS\n", sps);
+       return len;
+}
+
+static ssize_t ade7754_write_frequency(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7754_state *st = iio_dev_get_devdata(indio_dev);
+       unsigned long val;
+       int ret;
+       u8 reg, t;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               return ret;
+
+       mutex_lock(&indio_dev->mlock);
+
+       t = (26000 / val);
+       if (t > 0)
+               t--;
+
+       if (t > 1)
+               st->us->max_speed_hz = ADE7754_SPI_SLOW;
+       else
+               st->us->max_speed_hz = ADE7754_SPI_FAST;
+
+       ret = ade7754_spi_read_reg_8(dev,
+                       ADE7754_WAVMODE,
+                       &reg);
+       if (ret)
+               goto out;
+
+       reg &= ~(3 << 3);
+       reg |= t << 3;
+
+       ret = ade7754_spi_write_reg_8(dev,
+                       ADE7754_WAVMODE,
+                       reg);
+
+out:
+       mutex_unlock(&indio_dev->mlock);
+
+       return ret ? ret : len;
+}
+static IIO_DEV_ATTR_TEMP_RAW(ade7754_read_8bit);
+static IIO_CONST_ATTR(temp_offset, "129 C");
+static IIO_CONST_ATTR(temp_scale, "4 C");
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+               ade7754_read_frequency,
+               ade7754_write_frequency);
+
+static IIO_DEV_ATTR_RESET(ade7754_write_reset);
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("26000 13000 65000 33000");
+
+static IIO_CONST_ATTR(name, "ade7754");
+
+static struct attribute *ade7754_event_attributes[] = {
+       NULL
+};
+
+static struct attribute_group ade7754_event_attribute_group = {
+       .attrs = ade7754_event_attributes,
+};
+
+static struct attribute *ade7754_attributes[] = {
+       &iio_dev_attr_temp_raw.dev_attr.attr,
+       &iio_const_attr_temp_offset.dev_attr.attr,
+       &iio_const_attr_temp_scale.dev_attr.attr,
+       &iio_dev_attr_sampling_frequency.dev_attr.attr,
+       &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+       &iio_dev_attr_reset.dev_attr.attr,
+       &iio_const_attr_name.dev_attr.attr,
+       &iio_dev_attr_aenergy.dev_attr.attr,
+       &iio_dev_attr_laenergy.dev_attr.attr,
+       &iio_dev_attr_vaenergy.dev_attr.attr,
+       &iio_dev_attr_lvaenergy.dev_attr.attr,
+       &iio_dev_attr_vpeak.dev_attr.attr,
+       &iio_dev_attr_ipeak.dev_attr.attr,
+       &iio_dev_attr_aphcal.dev_attr.attr,
+       &iio_dev_attr_bphcal.dev_attr.attr,
+       &iio_dev_attr_cphcal.dev_attr.attr,
+       &iio_dev_attr_aapos.dev_attr.attr,
+       &iio_dev_attr_bapos.dev_attr.attr,
+       &iio_dev_attr_capos.dev_attr.attr,
+       &iio_dev_attr_wdiv.dev_attr.attr,
+       &iio_dev_attr_vadiv.dev_attr.attr,
+       &iio_dev_attr_cfnum.dev_attr.attr,
+       &iio_dev_attr_cfden.dev_attr.attr,
+       &iio_dev_attr_active_power_a_gain.dev_attr.attr,
+       &iio_dev_attr_active_power_b_gain.dev_attr.attr,
+       &iio_dev_attr_active_power_c_gain.dev_attr.attr,
+       &iio_dev_attr_airms.dev_attr.attr,
+       &iio_dev_attr_birms.dev_attr.attr,
+       &iio_dev_attr_cirms.dev_attr.attr,
+       &iio_dev_attr_avrms.dev_attr.attr,
+       &iio_dev_attr_bvrms.dev_attr.attr,
+       &iio_dev_attr_cvrms.dev_attr.attr,
+       &iio_dev_attr_airmsos.dev_attr.attr,
+       &iio_dev_attr_birmsos.dev_attr.attr,
+       &iio_dev_attr_cirmsos.dev_attr.attr,
+       &iio_dev_attr_avrmsos.dev_attr.attr,
+       &iio_dev_attr_bvrmsos.dev_attr.attr,
+       &iio_dev_attr_cvrmsos.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ade7754_attribute_group = {
+       .attrs = ade7754_attributes,
+};
+
+
+
+static int __devinit ade7754_probe(struct spi_device *spi)
+{
+       int ret, regdone = 0;
+       struct ade7754_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+       if (!st) {
+               ret =  -ENOMEM;
+               goto error_ret;
+       }
+       /* this is only used for removal purposes */
+       spi_set_drvdata(spi, st);
+
+       /* Allocate the comms buffers */
+       st->rx = kzalloc(sizeof(*st->rx)*ADE7754_MAX_RX, GFP_KERNEL);
+       if (st->rx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->tx = kzalloc(sizeof(*st->tx)*ADE7754_MAX_TX, GFP_KERNEL);
+       if (st->tx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_rx;
+       }
+       st->us = spi;
+       mutex_init(&st->buf_lock);
+       /* setup the industrialio driver allocated elements */
+       st->indio_dev = iio_allocate_device();
+       if (st->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_tx;
+       }
+
+       st->indio_dev->dev.parent = &spi->dev;
+       st->indio_dev->num_interrupt_lines = 1;
+       st->indio_dev->event_attrs = &ade7754_event_attribute_group;
+       st->indio_dev->attrs = &ade7754_attribute_group;
+       st->indio_dev->dev_data = (void *)(st);
+       st->indio_dev->driver_module = THIS_MODULE;
+       st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = ade7754_configure_ring(st->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       ret = iio_device_register(st->indio_dev);
+       if (ret)
+               goto error_unreg_ring_funcs;
+       regdone = 1;
+
+       ret = ade7754_initialize_ring(st->indio_dev->ring);
+       if (ret) {
+               printk(KERN_ERR "failed to initialize the ring\n");
+               goto error_unreg_ring_funcs;
+       }
+
+       if (spi->irq) {
+               ret = iio_register_interrupt_line(spi->irq,
+                               st->indio_dev,
+                               0,
+                               IRQF_TRIGGER_FALLING,
+                               "ade7754");
+               if (ret)
+                       goto error_uninitialize_ring;
+
+               ret = ade7754_probe_trigger(st->indio_dev);
+               if (ret)
+                       goto error_unregister_line;
+       }
+
+       /* Get the device into a sane initial state */
+       ret = ade7754_initial_setup(st);
+       if (ret)
+               goto error_remove_trigger;
+       return 0;
+
+error_remove_trigger:
+       if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+               ade7754_remove_trigger(st->indio_dev);
+error_unregister_line:
+       if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+               iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+       ade7754_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+       ade7754_unconfigure_ring(st->indio_dev);
+error_free_dev:
+       if (regdone)
+               iio_device_unregister(st->indio_dev);
+       else
+               iio_free_device(st->indio_dev);
+error_free_tx:
+       kfree(st->tx);
+error_free_rx:
+       kfree(st->rx);
+error_free_st:
+       kfree(st);
+error_ret:
+       return ret;
+}
+
+/* fixme, confirm ordering in this function */
+static int ade7754_remove(struct spi_device *spi)
+{
+       int ret;
+       struct ade7754_state *st = spi_get_drvdata(spi);
+       struct iio_dev *indio_dev = st->indio_dev;
+
+       ret = ade7754_stop_device(&(indio_dev->dev));
+       if (ret)
+               goto err_ret;
+
+       flush_scheduled_work();
+
+       ade7754_remove_trigger(indio_dev);
+       if (spi->irq)
+               iio_unregister_interrupt_line(indio_dev, 0);
+
+       ade7754_uninitialize_ring(indio_dev->ring);
+       ade7754_unconfigure_ring(indio_dev);
+       iio_device_unregister(indio_dev);
+       kfree(st->tx);
+       kfree(st->rx);
+       kfree(st);
+
+       return 0;
+
+err_ret:
+       return ret;
+}
+
+static struct spi_driver ade7754_driver = {
+       .driver = {
+               .name = "ade7754",
+               .owner = THIS_MODULE,
+       },
+       .probe = ade7754_probe,
+       .remove = __devexit_p(ade7754_remove),
+};
+
+static __init int ade7754_init(void)
+{
+       return spi_register_driver(&ade7754_driver);
+}
+module_init(ade7754_init);
+
+static __exit void ade7754_exit(void)
+{
+       spi_unregister_driver(&ade7754_driver);
+}
+module_exit(ade7754_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADE7754 Polyphase Multifunction Energy Metering IC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/meter/ade7754.h b/drivers/staging/iio/meter/ade7754.h
new file mode 100644 (file)
index 0000000..f6a3e4b
--- /dev/null
@@ -0,0 +1,161 @@
+#ifndef _ADE7754_H
+#define _ADE7754_H
+
+#define ADE7754_AENERGY   0x01
+#define ADE7754_RAENERGY  0x02
+#define ADE7754_LAENERGY  0x03
+#define ADE7754_VAENERGY  0x04
+#define ADE7754_RVAENERGY 0x05
+#define ADE7754_LVAENERGY 0x06
+#define ADE7754_PERIOD    0x07
+#define ADE7754_TEMP      0x08
+#define ADE7754_WFORM     0x09
+#define ADE7754_OPMODE    0x0A
+#define ADE7754_MMODE     0x0B
+#define ADE7754_WAVMODE   0x0C
+#define ADE7754_WATMODE   0x0D
+#define ADE7754_VAMODE    0x0E
+#define ADE7754_IRQEN     0x0F
+#define ADE7754_STATUS    0x10
+#define ADE7754_RSTATUS   0x11
+#define ADE7754_ZXTOUT    0x12
+#define ADE7754_LINCYC    0x13
+#define ADE7754_SAGCYC    0x14
+#define ADE7754_SAGLVL    0x15
+#define ADE7754_VPEAK     0x16
+#define ADE7754_IPEAK     0x17
+#define ADE7754_GAIN      0x18
+#define ADE7754_AWG       0x19
+#define ADE7754_BWG       0x1A
+#define ADE7754_CWG       0x1B
+#define ADE7754_AVAG      0x1C
+#define ADE7754_BVAG      0x1D
+#define ADE7754_CVAG      0x1E
+#define ADE7754_APHCAL    0x1F
+#define ADE7754_BPHCAL    0x20
+#define ADE7754_CPHCAL    0x21
+#define ADE7754_AAPOS     0x22
+#define ADE7754_BAPOS     0x23
+#define ADE7754_CAPOS     0x24
+#define ADE7754_CFNUM     0x25
+#define ADE7754_CFDEN     0x26
+#define ADE7754_WDIV      0x27
+#define ADE7754_VADIV     0x28
+#define ADE7754_AIRMS     0x29
+#define ADE7754_BIRMS     0x2A
+#define ADE7754_CIRMS     0x2B
+#define ADE7754_AVRMS     0x2C
+#define ADE7754_BVRMS     0x2D
+#define ADE7754_CVRMS     0x2E
+#define ADE7754_AIRMSOS   0x2F
+#define ADE7754_BIRMSOS   0x30
+#define ADE7754_CIRMSOS   0x31
+#define ADE7754_AVRMSOS   0x32
+#define ADE7754_BVRMSOS   0x33
+#define ADE7754_CVRMSOS   0x34
+#define ADE7754_AAPGAIN   0x35
+#define ADE7754_BAPGAIN   0x36
+#define ADE7754_CAPGAIN   0x37
+#define ADE7754_AVGAIN    0x38
+#define ADE7754_BVGAIN    0x39
+#define ADE7754_CVGAIN    0x3A
+#define ADE7754_CHKSUM    0x3E
+#define ADE7754_VERSION   0x3F
+
+#define ADE7754_READ_REG(a)    a
+#define ADE7754_WRITE_REG(a) ((a) | 0x80)
+
+#define ADE7754_MAX_TX    4
+#define ADE7754_MAX_RX    4
+#define ADE7754_STARTUP_DELAY 1
+
+#define ADE7754_SPI_SLOW       (u32)(300 * 1000)
+#define ADE7754_SPI_BURST      (u32)(1000 * 1000)
+#define ADE7754_SPI_FAST       (u32)(2000 * 1000)
+
+#define DRIVER_NAME            "ade7754"
+
+/**
+ * struct ade7754_state - device instance specific data
+ * @us:                        actual spi_device
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter:             used to check if new interrupt has been triggered
+ * @last_timestamp:    passing timestamp from th to bh of interrupt handler
+ * @indio_dev:         industrial I/O device structure
+ * @trig:              data ready trigger registered with iio
+ * @tx:                        transmit buffer
+ * @rx:                        recieve buffer
+ * @buf_lock:          mutex to protect tx and rx
+ **/
+struct ade7754_state {
+       struct spi_device               *us;
+       struct work_struct              work_trigger_to_ring;
+       s64                             last_timestamp;
+       struct iio_dev                  *indio_dev;
+       struct iio_trigger              *trig;
+       u8                              *tx;
+       u8                              *rx;
+       struct mutex                    buf_lock;
+};
+#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
+
+enum ade7754_scan {
+       ADE7754_SCAN_PHA_V,
+       ADE7754_SCAN_PHB_V,
+       ADE7754_SCAN_PHC_V,
+       ADE7754_SCAN_PHA_I,
+       ADE7754_SCAN_PHB_I,
+       ADE7754_SCAN_PHC_I,
+};
+
+void ade7754_remove_trigger(struct iio_dev *indio_dev);
+int ade7754_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t ade7754_read_data_from_ring(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf);
+
+
+int ade7754_configure_ring(struct iio_dev *indio_dev);
+void ade7754_unconfigure_ring(struct iio_dev *indio_dev);
+
+int ade7754_initialize_ring(struct iio_ring_buffer *ring);
+void ade7754_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void ade7754_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7754_probe_trigger(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline ssize_t
+ade7754_read_data_from_ring(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       return 0;
+}
+
+static int ade7754_configure_ring(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+static inline void ade7754_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7754_initialize_ring(struct iio_ring_buffer *ring)
+{
+       return 0;
+}
+static inline void ade7754_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+#endif /* CONFIG_IIO_RING_BUFFER */
+
+#endif
diff --git a/drivers/staging/iio/meter/ade7758.h b/drivers/staging/iio/meter/ade7758.h
new file mode 100644 (file)
index 0000000..df5bb7b
--- /dev/null
@@ -0,0 +1,171 @@
+#ifndef _ADE7758_H
+#define _ADE7758_H
+
+#define ADE7758_AWATTHR   0x01
+#define ADE7758_BWATTHR   0x02
+#define ADE7758_CWATTHR   0x03
+#define ADE7758_AVARHR    0x04
+#define ADE7758_BVARHR    0x05
+#define ADE7758_CVARHR    0x06
+#define ADE7758_AVAHR     0x07
+#define ADE7758_BVAHR     0x08
+#define ADE7758_CVAHR     0x09
+#define ADE7758_AIRMS     0x0A
+#define ADE7758_BIRMS     0x0B
+#define ADE7758_CIRMS     0x0C
+#define ADE7758_AVRMS     0x0D
+#define ADE7758_BVRMS     0x0E
+#define ADE7758_CVRMS     0x0F
+#define ADE7758_FREQ      0x10
+#define ADE7758_TEMP      0x11
+#define ADE7758_WFORM     0x12
+#define ADE7758_OPMODE    0x13
+#define ADE7758_MMODE     0x14
+#define ADE7758_WAVMODE   0x15
+#define ADE7758_COMPMODE  0x16
+#define ADE7758_LCYCMODE  0x17
+#define ADE7758_MASK      0x18
+#define ADE7758_STATUS    0x19
+#define ADE7758_RSTATUS   0x1A
+#define ADE7758_ZXTOUT    0x1B
+#define ADE7758_LINECYC   0x1C
+#define ADE7758_SAGCYC    0x1D
+#define ADE7758_SAGLVL    0x1E
+#define ADE7758_VPINTLVL  0x1F
+#define ADE7758_IPINTLVL  0x20
+#define ADE7758_VPEAK     0x21
+#define ADE7758_IPEAK     0x22
+#define ADE7758_GAIN      0x23
+#define ADE7758_AVRMSGAIN 0x24
+#define ADE7758_BVRMSGAIN 0x25
+#define ADE7758_CVRMSGAIN 0x26
+#define ADE7758_AIGAIN    0x27
+#define ADE7758_BIGAIN    0x28
+#define ADE7758_CIGAIN    0x29
+#define ADE7758_AWG       0x2A
+#define ADE7758_BWG       0x2B
+#define ADE7758_CWG       0x2C
+#define ADE7758_AVARG     0x2D
+#define ADE7758_BVARG     0x2E
+#define ADE7758_CVARG     0x2F
+#define ADE7758_AVAG      0x30
+#define ADE7758_BVAG      0x31
+#define ADE7758_CVAG      0x32
+#define ADE7758_AVRMSOS   0x33
+#define ADE7758_BVRMSOS   0x34
+#define ADE7758_CVRMSOS   0x35
+#define ADE7758_AIRMSOS   0x36
+#define ADE7758_BIRMSOS   0x37
+#define ADE7758_CIRMSOS   0x38
+#define ADE7758_AWAITOS   0x39
+#define ADE7758_BWAITOS   0x3A
+#define ADE7758_CWAITOS   0x3B
+#define ADE7758_AVAROS    0x3C
+#define ADE7758_BVAROS    0x3D
+#define ADE7758_CVAROS    0x3E
+#define ADE7758_APHCAL    0x3F
+#define ADE7758_BPHCAL    0x40
+#define ADE7758_CPHCAL    0x41
+#define ADE7758_WDIV      0x42
+#define ADE7758_VADIV     0x44
+#define ADE7758_VARDIV    0x43
+#define ADE7758_APCFNUM   0x45
+#define ADE7758_APCFDEN   0x46
+#define ADE7758_VARCFNUM  0x47
+#define ADE7758_VARCFDEN  0x48
+#define ADE7758_CHKSUM    0x7E
+#define ADE7758_VERSION   0x7F
+
+#define ADE7758_READ_REG(a)    a
+#define ADE7758_WRITE_REG(a) ((a) | 0x80)
+
+#define ADE7758_MAX_TX    8
+#define ADE7758_MAX_RX    4
+#define ADE7758_STARTUP_DELAY 1
+
+#define ADE7758_SPI_SLOW       (u32)(300 * 1000)
+#define ADE7758_SPI_BURST      (u32)(1000 * 1000)
+#define ADE7758_SPI_FAST       (u32)(2000 * 1000)
+
+#define DRIVER_NAME            "ade7758"
+
+/**
+ * struct ade7758_state - device instance specific data
+ * @us:                        actual spi_device
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter:             used to check if new interrupt has been triggered
+ * @last_timestamp:    passing timestamp from th to bh of interrupt handler
+ * @indio_dev:         industrial I/O device structure
+ * @trig:              data ready trigger registered with iio
+ * @tx:                        transmit buffer
+ * @rx:                        recieve buffer
+ * @buf_lock:          mutex to protect tx and rx
+ **/
+struct ade7758_state {
+       struct spi_device               *us;
+       struct work_struct              work_trigger_to_ring;
+       s64                             last_timestamp;
+       struct iio_dev                  *indio_dev;
+       struct iio_trigger              *trig;
+       u8                              *tx;
+       u8                              *rx;
+       struct mutex                    buf_lock;
+};
+#ifdef CONFIG_IIO_RING_BUFFER
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
+
+enum ade7758_scan {
+       ADE7758_SCAN_WFORM,
+};
+
+void ade7758_remove_trigger(struct iio_dev *indio_dev);
+int ade7758_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t ade7758_read_data_from_ring(struct device *dev,
+               struct device_attribute *attr,
+               char *buf);
+
+
+int ade7758_configure_ring(struct iio_dev *indio_dev);
+void ade7758_unconfigure_ring(struct iio_dev *indio_dev);
+
+int ade7758_initialize_ring(struct iio_ring_buffer *ring);
+void ade7758_uninitialize_ring(struct iio_ring_buffer *ring);
+int ade7758_set_irq(struct device *dev, bool enable);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void ade7758_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7758_probe_trigger(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline ssize_t
+ade7758_read_data_from_ring(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return 0;
+}
+
+static int ade7758_configure_ring(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+static inline void ade7758_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7758_initialize_ring(struct iio_ring_buffer *ring)
+{
+       return 0;
+}
+static inline void ade7758_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+#endif /* CONFIG_IIO_RING_BUFFER */
+
+#endif
diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c
new file mode 100644 (file)
index 0000000..b7634cb
--- /dev/null
@@ -0,0 +1,866 @@
+/*
+ * ADE7758 Polyphase Multifunction Energy Metering IC Driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "meter.h"
+#include "ade7758.h"
+
+int ade7758_spi_write_reg_8(struct device *dev,
+               u8 reg_address,
+               u8 val)
+{
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7758_state *st = iio_dev_get_devdata(indio_dev);
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7758_WRITE_REG(reg_address);
+       st->tx[1] = val;
+
+       ret = spi_write(st->us, st->tx, 2);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static int ade7758_spi_write_reg_16(struct device *dev,
+               u8 reg_address,
+               u16 value)
+{
+       int ret;
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7758_state *st = iio_dev_get_devdata(indio_dev);
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 3,
+               }
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7758_WRITE_REG(reg_address);
+       st->tx[1] = (value >> 8) & 0xFF;
+       st->tx[2] = value & 0xFF;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->us, &msg);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static int ade7758_spi_write_reg_24(struct device *dev,
+               u8 reg_address,
+               u32 value)
+{
+       int ret;
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7758_state *st = iio_dev_get_devdata(indio_dev);
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 4,
+               }
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7758_WRITE_REG(reg_address);
+       st->tx[1] = (value >> 16) & 0xFF;
+       st->tx[2] = (value >> 8) & 0xFF;
+       st->tx[3] = value & 0xFF;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->us, &msg);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static int ade7758_spi_read_reg_8(struct device *dev,
+               u8 reg_address,
+               u8 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7758_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .rx_buf = st->rx,
+                       .bits_per_word = 8,
+                       .len = 2,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7758_READ_REG(reg_address);
+       st->tx[1] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->us, &msg);
+       if (ret) {
+               dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X",
+                               reg_address);
+               goto error_ret;
+       }
+       *val = st->rx[1];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static int ade7758_spi_read_reg_16(struct device *dev,
+               u8 reg_address,
+               u16 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7758_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .rx_buf = st->rx,
+                       .bits_per_word = 8,
+                       .len = 3,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7758_READ_REG(reg_address);
+       st->tx[1] = 0;
+       st->tx[2] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->us, &msg);
+       if (ret) {
+               dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
+                               reg_address);
+               goto error_ret;
+       }
+       *val = (st->rx[1] << 8) | st->rx[2];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static int ade7758_spi_read_reg_24(struct device *dev,
+               u8 reg_address,
+               u32 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7758_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .rx_buf = st->rx,
+                       .bits_per_word = 8,
+                       .len = 4,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7758_READ_REG(reg_address);
+       st->tx[1] = 0;
+       st->tx[2] = 0;
+       st->tx[3] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->us, &msg);
+       if (ret) {
+               dev_err(&st->us->dev, "problem when reading 24 bit register 0x%02X",
+                               reg_address);
+               goto error_ret;
+       }
+       *val = (st->rx[1] << 16) | (st->rx[2] << 8) | st->rx[3];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static ssize_t ade7758_read_8bit(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u8 val = 0;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = ade7758_spi_read_reg_8(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7758_read_16bit(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u16 val = 0;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = ade7758_spi_read_reg_16(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7758_read_24bit(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u32 val = 0;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = ade7758_spi_read_reg_24(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%u\n", val & 0xFFFFFF);
+}
+
+static ssize_t ade7758_write_8bit(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       int ret;
+       long val;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               goto error_ret;
+       ret = ade7758_spi_write_reg_8(dev, this_attr->address, val);
+
+error_ret:
+       return ret ? ret : len;
+}
+
+static ssize_t ade7758_write_16bit(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       int ret;
+       long val;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               goto error_ret;
+       ret = ade7758_spi_write_reg_16(dev, this_attr->address, val);
+
+error_ret:
+       return ret ? ret : len;
+}
+
+int ade7758_reset(struct device *dev)
+{
+       int ret;
+       u8 val;
+       ade7758_spi_read_reg_8(dev,
+                       ADE7758_OPMODE,
+                       &val);
+       val |= 1 << 6; /* Software Chip Reset */
+       ret = ade7758_spi_write_reg_8(dev,
+                       ADE7758_OPMODE,
+                       val);
+
+       return ret;
+}
+
+static ssize_t ade7758_write_reset(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf, size_t len)
+{
+       if (len < 1)
+               return -1;
+       switch (buf[0]) {
+       case '1':
+       case 'y':
+       case 'Y':
+               return ade7758_reset(dev);
+       }
+       return -1;
+}
+
+static IIO_DEV_ATTR_VPEAK(S_IWUSR | S_IRUGO,
+               ade7758_read_8bit,
+               ade7758_write_8bit,
+               ADE7758_VPEAK);
+static IIO_DEV_ATTR_IPEAK(S_IWUSR | S_IRUGO,
+               ade7758_read_8bit,
+               ade7758_write_8bit,
+               ADE7758_VPEAK);
+static IIO_DEV_ATTR_APHCAL(S_IWUSR | S_IRUGO,
+               ade7758_read_8bit,
+               ade7758_write_8bit,
+               ADE7758_APHCAL);
+static IIO_DEV_ATTR_BPHCAL(S_IWUSR | S_IRUGO,
+               ade7758_read_8bit,
+               ade7758_write_8bit,
+               ADE7758_BPHCAL);
+static IIO_DEV_ATTR_CPHCAL(S_IWUSR | S_IRUGO,
+               ade7758_read_8bit,
+               ade7758_write_8bit,
+               ADE7758_CPHCAL);
+static IIO_DEV_ATTR_WDIV(S_IWUSR | S_IRUGO,
+               ade7758_read_8bit,
+               ade7758_write_8bit,
+               ADE7758_WDIV);
+static IIO_DEV_ATTR_VADIV(S_IWUSR | S_IRUGO,
+               ade7758_read_8bit,
+               ade7758_write_8bit,
+               ADE7758_VADIV);
+static IIO_DEV_ATTR_AIRMS(S_IRUGO,
+               ade7758_read_24bit,
+               NULL,
+               ADE7758_AIRMS);
+static IIO_DEV_ATTR_BIRMS(S_IRUGO,
+               ade7758_read_24bit,
+               NULL,
+               ADE7758_BIRMS);
+static IIO_DEV_ATTR_CIRMS(S_IRUGO,
+               ade7758_read_24bit,
+               NULL,
+               ADE7758_CIRMS);
+static IIO_DEV_ATTR_AVRMS(S_IRUGO,
+               ade7758_read_24bit,
+               NULL,
+               ADE7758_AVRMS);
+static IIO_DEV_ATTR_BVRMS(S_IRUGO,
+               ade7758_read_24bit,
+               NULL,
+               ADE7758_BVRMS);
+static IIO_DEV_ATTR_CVRMS(S_IRUGO,
+               ade7758_read_24bit,
+               NULL,
+               ADE7758_CVRMS);
+static IIO_DEV_ATTR_AIRMSOS(S_IWUSR | S_IRUGO,
+               ade7758_read_16bit,
+               ade7758_write_16bit,
+               ADE7758_AIRMSOS);
+static IIO_DEV_ATTR_BIRMSOS(S_IWUSR | S_IRUGO,
+               ade7758_read_16bit,
+               ade7758_write_16bit,
+               ADE7758_BIRMSOS);
+static IIO_DEV_ATTR_CIRMSOS(S_IWUSR | S_IRUGO,
+               ade7758_read_16bit,
+               ade7758_write_16bit,
+               ADE7758_CIRMSOS);
+static IIO_DEV_ATTR_AVRMSOS(S_IWUSR | S_IRUGO,
+               ade7758_read_16bit,
+               ade7758_write_16bit,
+               ADE7758_AVRMSOS);
+static IIO_DEV_ATTR_BVRMSOS(S_IWUSR | S_IRUGO,
+               ade7758_read_16bit,
+               ade7758_write_16bit,
+               ADE7758_BVRMSOS);
+static IIO_DEV_ATTR_CVRMSOS(S_IWUSR | S_IRUGO,
+               ade7758_read_16bit,
+               ade7758_write_16bit,
+               ADE7758_CVRMSOS);
+static IIO_DEV_ATTR_AIGAIN(S_IWUSR | S_IRUGO,
+               ade7758_read_16bit,
+               ade7758_write_16bit,
+               ADE7758_AIGAIN);
+static IIO_DEV_ATTR_BIGAIN(S_IWUSR | S_IRUGO,
+               ade7758_read_16bit,
+               ade7758_write_16bit,
+               ADE7758_BIGAIN);
+static IIO_DEV_ATTR_CIGAIN(S_IWUSR | S_IRUGO,
+               ade7758_read_16bit,
+               ade7758_write_16bit,
+               ADE7758_CIGAIN);
+static IIO_DEV_ATTR_AVRMSGAIN(S_IWUSR | S_IRUGO,
+               ade7758_read_16bit,
+               ade7758_write_16bit,
+               ADE7758_AVRMSGAIN);
+static IIO_DEV_ATTR_BVRMSGAIN(S_IWUSR | S_IRUGO,
+               ade7758_read_16bit,
+               ade7758_write_16bit,
+               ADE7758_BVRMSGAIN);
+static IIO_DEV_ATTR_CVRMSGAIN(S_IWUSR | S_IRUGO,
+               ade7758_read_16bit,
+               ade7758_write_16bit,
+               ADE7758_CVRMSGAIN);
+
+int ade7758_set_irq(struct device *dev, bool enable)
+{
+       int ret;
+       u32 irqen;
+       ret = ade7758_spi_read_reg_24(dev, ADE7758_MASK, &irqen);
+       if (ret)
+               goto error_ret;
+
+       if (enable)
+               irqen |= 1 << 16; /* Enables an interrupt when a data is
+                                    present in the waveform register */
+       else
+               irqen &= ~(1 << 16);
+
+       ret = ade7758_spi_write_reg_24(dev, ADE7758_MASK, irqen);
+       if (ret)
+               goto error_ret;
+
+error_ret:
+       return ret;
+}
+
+/* Power down the device */
+static int ade7758_stop_device(struct device *dev)
+{
+       int ret;
+       u8 val;
+       ade7758_spi_read_reg_8(dev,
+                       ADE7758_OPMODE,
+                       &val);
+       val |= 7 << 3;  /* ADE7758 powered down */
+       ret = ade7758_spi_write_reg_8(dev,
+                       ADE7758_OPMODE,
+                       val);
+
+       return ret;
+}
+
+static int ade7758_initial_setup(struct ade7758_state *st)
+{
+       int ret;
+       struct device *dev = &st->indio_dev->dev;
+
+       /* use low spi speed for init */
+       st->us->mode = SPI_MODE_3;
+       spi_setup(st->us);
+
+       /* Disable IRQ */
+       ret = ade7758_set_irq(dev, false);
+       if (ret) {
+               dev_err(dev, "disable irq failed");
+               goto err_ret;
+       }
+
+       ade7758_reset(dev);
+       msleep(ADE7758_STARTUP_DELAY);
+
+err_ret:
+       return ret;
+}
+
+static ssize_t ade7758_read_frequency(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret, len = 0;
+       u8 t;
+       int sps;
+       ret = ade7758_spi_read_reg_8(dev,
+                       ADE7758_WAVMODE,
+                       &t);
+       if (ret)
+               return ret;
+
+       t = (t >> 5) & 0x3;
+       sps = 26040 / (1 << t);
+
+       len = sprintf(buf, "%d SPS\n", sps);
+       return len;
+}
+
+static ssize_t ade7758_write_frequency(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7758_state *st = iio_dev_get_devdata(indio_dev);
+       unsigned long val;
+       int ret;
+       u8 reg, t;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               return ret;
+
+       mutex_lock(&indio_dev->mlock);
+
+       t = (26040 / val);
+       if (t > 0)
+               t >>= 1;
+
+       if (t > 1)
+               st->us->max_speed_hz = ADE7758_SPI_SLOW;
+       else
+               st->us->max_speed_hz = ADE7758_SPI_FAST;
+
+       ret = ade7758_spi_read_reg_8(dev,
+                       ADE7758_WAVMODE,
+                       &reg);
+       if (ret)
+               goto out;
+
+       reg &= ~(5 << 3);
+       reg |= t << 5;
+
+       ret = ade7758_spi_write_reg_8(dev,
+                       ADE7758_WAVMODE,
+                       reg);
+
+out:
+       mutex_unlock(&indio_dev->mlock);
+
+       return ret ? ret : len;
+}
+
+static ssize_t ade7758_read_waveform_type(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret, len = 0;
+       u8 t;
+       ret = ade7758_spi_read_reg_8(dev,
+                       ADE7758_WAVMODE,
+                       &t);
+       if (ret)
+               return ret;
+
+       t = (t >> 2) & 0x7;
+
+       len = sprintf(buf, "%d\n", t);
+
+       return len;
+}
+
+static ssize_t ade7758_write_waveform_type(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       unsigned long val;
+       int ret;
+       u8 reg;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               return ret;
+
+       if (val > 4)
+               return -EINVAL;
+
+       mutex_lock(&indio_dev->mlock);
+
+       ret = ade7758_spi_read_reg_8(dev,
+                       ADE7758_WAVMODE,
+                       &reg);
+       if (ret)
+               goto out;
+
+       reg &= ~(7 << 2);
+       reg |= val << 2;
+
+       ret = ade7758_spi_write_reg_8(dev,
+                       ADE7758_WAVMODE,
+                       reg);
+
+out:
+       mutex_unlock(&indio_dev->mlock);
+
+       return ret ? ret : len;
+}
+
+static IIO_DEV_ATTR_TEMP_RAW(ade7758_read_8bit);
+static IIO_CONST_ATTR(temp_offset, "129 C");
+static IIO_CONST_ATTR(temp_scale, "4 C");
+
+static IIO_DEV_ATTR_AWATTHR(ade7758_read_16bit,
+               ADE7758_AWATTHR);
+static IIO_DEV_ATTR_BWATTHR(ade7758_read_16bit,
+               ADE7758_BWATTHR);
+static IIO_DEV_ATTR_CWATTHR(ade7758_read_16bit,
+               ADE7758_CWATTHR);
+static IIO_DEV_ATTR_AVARHR(ade7758_read_16bit,
+               ADE7758_AVARHR);
+static IIO_DEV_ATTR_BVARHR(ade7758_read_16bit,
+               ADE7758_BVARHR);
+static IIO_DEV_ATTR_CVARHR(ade7758_read_16bit,
+               ADE7758_CVARHR);
+static IIO_DEV_ATTR_AVAHR(ade7758_read_16bit,
+               ADE7758_AVAHR);
+static IIO_DEV_ATTR_BVAHR(ade7758_read_16bit,
+               ADE7758_BVAHR);
+static IIO_DEV_ATTR_CVAHR(ade7758_read_16bit,
+               ADE7758_CVAHR);
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+               ade7758_read_frequency,
+               ade7758_write_frequency);
+
+/**
+ * IIO_DEV_ATTR_WAVEFORM_TYPE - set the type of waveform.
+ * @_mode: sysfs file mode/permissions
+ * @_show: output method for the attribute
+ * @_store: input method for the attribute
+ **/
+#define IIO_DEV_ATTR_WAVEFORM_TYPE(_mode, _show, _store)                       \
+       IIO_DEVICE_ATTR(waveform_type, _mode, _show, _store, 0)
+
+static IIO_DEV_ATTR_WAVEFORM_TYPE(S_IWUSR | S_IRUGO,
+               ade7758_read_waveform_type,
+               ade7758_write_waveform_type);
+
+static IIO_DEV_ATTR_RESET(ade7758_write_reset);
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("26000 13000 65000 33000");
+
+static IIO_CONST_ATTR(name, "ade7758");
+
+static struct attribute *ade7758_event_attributes[] = {
+       NULL
+};
+
+static struct attribute_group ade7758_event_attribute_group = {
+       .attrs = ade7758_event_attributes,
+};
+
+static struct attribute *ade7758_attributes[] = {
+       &iio_dev_attr_temp_raw.dev_attr.attr,
+       &iio_const_attr_temp_offset.dev_attr.attr,
+       &iio_const_attr_temp_scale.dev_attr.attr,
+       &iio_dev_attr_sampling_frequency.dev_attr.attr,
+       &iio_dev_attr_waveform_type.dev_attr.attr,
+       &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+       &iio_dev_attr_reset.dev_attr.attr,
+       &iio_const_attr_name.dev_attr.attr,
+       &iio_dev_attr_awatthr.dev_attr.attr,
+       &iio_dev_attr_bwatthr.dev_attr.attr,
+       &iio_dev_attr_cwatthr.dev_attr.attr,
+       &iio_dev_attr_avarhr.dev_attr.attr,
+       &iio_dev_attr_bvarhr.dev_attr.attr,
+       &iio_dev_attr_cvarhr.dev_attr.attr,
+       &iio_dev_attr_avahr.dev_attr.attr,
+       &iio_dev_attr_bvahr.dev_attr.attr,
+       &iio_dev_attr_cvahr.dev_attr.attr,
+       &iio_dev_attr_vpeak.dev_attr.attr,
+       &iio_dev_attr_ipeak.dev_attr.attr,
+       &iio_dev_attr_aphcal.dev_attr.attr,
+       &iio_dev_attr_bphcal.dev_attr.attr,
+       &iio_dev_attr_cphcal.dev_attr.attr,
+       &iio_dev_attr_wdiv.dev_attr.attr,
+       &iio_dev_attr_vadiv.dev_attr.attr,
+       &iio_dev_attr_airms.dev_attr.attr,
+       &iio_dev_attr_birms.dev_attr.attr,
+       &iio_dev_attr_cirms.dev_attr.attr,
+       &iio_dev_attr_avrms.dev_attr.attr,
+       &iio_dev_attr_bvrms.dev_attr.attr,
+       &iio_dev_attr_cvrms.dev_attr.attr,
+       &iio_dev_attr_aigain.dev_attr.attr,
+       &iio_dev_attr_bigain.dev_attr.attr,
+       &iio_dev_attr_cigain.dev_attr.attr,
+       &iio_dev_attr_avrmsgain.dev_attr.attr,
+       &iio_dev_attr_bvrmsgain.dev_attr.attr,
+       &iio_dev_attr_cvrmsgain.dev_attr.attr,
+       &iio_dev_attr_airmsos.dev_attr.attr,
+       &iio_dev_attr_birmsos.dev_attr.attr,
+       &iio_dev_attr_cirmsos.dev_attr.attr,
+       &iio_dev_attr_avrmsos.dev_attr.attr,
+       &iio_dev_attr_bvrmsos.dev_attr.attr,
+       &iio_dev_attr_cvrmsos.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ade7758_attribute_group = {
+       .attrs = ade7758_attributes,
+};
+
+
+
+static int __devinit ade7758_probe(struct spi_device *spi)
+{
+       int ret, regdone = 0;
+       struct ade7758_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+       if (!st) {
+               ret =  -ENOMEM;
+               goto error_ret;
+       }
+       /* this is only used for removal purposes */
+       spi_set_drvdata(spi, st);
+
+       /* Allocate the comms buffers */
+       st->rx = kzalloc(sizeof(*st->rx)*ADE7758_MAX_RX, GFP_KERNEL);
+       if (st->rx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->tx = kzalloc(sizeof(*st->tx)*ADE7758_MAX_TX, GFP_KERNEL);
+       if (st->tx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_rx;
+       }
+       st->us = spi;
+       mutex_init(&st->buf_lock);
+       /* setup the industrialio driver allocated elements */
+       st->indio_dev = iio_allocate_device();
+       if (st->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_tx;
+       }
+
+       st->indio_dev->dev.parent = &spi->dev;
+       st->indio_dev->num_interrupt_lines = 1;
+       st->indio_dev->event_attrs = &ade7758_event_attribute_group;
+       st->indio_dev->attrs = &ade7758_attribute_group;
+       st->indio_dev->dev_data = (void *)(st);
+       st->indio_dev->driver_module = THIS_MODULE;
+       st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = ade7758_configure_ring(st->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       ret = iio_device_register(st->indio_dev);
+       if (ret)
+               goto error_unreg_ring_funcs;
+       regdone = 1;
+
+       ret = ade7758_initialize_ring(st->indio_dev->ring);
+       if (ret) {
+               printk(KERN_ERR "failed to initialize the ring\n");
+               goto error_unreg_ring_funcs;
+       }
+
+       if (spi->irq) {
+               ret = iio_register_interrupt_line(spi->irq,
+                               st->indio_dev,
+                               0,
+                               IRQF_TRIGGER_FALLING,
+                               "ade7758");
+               if (ret)
+                       goto error_uninitialize_ring;
+
+               ret = ade7758_probe_trigger(st->indio_dev);
+               if (ret)
+                       goto error_unregister_line;
+       }
+
+       /* Get the device into a sane initial state */
+       ret = ade7758_initial_setup(st);
+       if (ret)
+               goto error_remove_trigger;
+       return 0;
+
+error_remove_trigger:
+       if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+               ade7758_remove_trigger(st->indio_dev);
+error_unregister_line:
+       if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+               iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+       ade7758_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+       ade7758_unconfigure_ring(st->indio_dev);
+error_free_dev:
+       if (regdone)
+               iio_device_unregister(st->indio_dev);
+       else
+               iio_free_device(st->indio_dev);
+error_free_tx:
+       kfree(st->tx);
+error_free_rx:
+       kfree(st->rx);
+error_free_st:
+       kfree(st);
+error_ret:
+       return ret;
+}
+
+static int ade7758_remove(struct spi_device *spi)
+{
+       int ret;
+       struct ade7758_state *st = spi_get_drvdata(spi);
+       struct iio_dev *indio_dev = st->indio_dev;
+
+       ret = ade7758_stop_device(&(indio_dev->dev));
+       if (ret)
+               goto err_ret;
+
+       flush_scheduled_work();
+
+       ade7758_remove_trigger(indio_dev);
+       if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
+               iio_unregister_interrupt_line(indio_dev, 0);
+
+       ade7758_uninitialize_ring(indio_dev->ring);
+       iio_device_unregister(indio_dev);
+       ade7758_unconfigure_ring(indio_dev);
+       kfree(st->tx);
+       kfree(st->rx);
+       kfree(st);
+
+       return 0;
+
+err_ret:
+       return ret;
+}
+
+static struct spi_driver ade7758_driver = {
+       .driver = {
+               .name = "ade7758",
+               .owner = THIS_MODULE,
+       },
+       .probe = ade7758_probe,
+       .remove = __devexit_p(ade7758_remove),
+};
+
+static __init int ade7758_init(void)
+{
+       return spi_register_driver(&ade7758_driver);
+}
+module_init(ade7758_init);
+
+static __exit void ade7758_exit(void)
+{
+       spi_unregister_driver(&ade7758_driver);
+}
+module_exit(ade7758_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADE7758 Polyphase Multifunction Energy Metering IC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c
new file mode 100644 (file)
index 0000000..274b4a0
--- /dev/null
@@ -0,0 +1,212 @@
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../ring_sw.h"
+#include "../accel/accel.h"
+#include "../trigger.h"
+#include "ade7758.h"
+
+/**
+ * combine_8_to_32() utility function to munge to u8s into u32
+ **/
+static inline u32 combine_8_to_32(u8 lower, u8 mid, u8 upper)
+{
+       u32 _lower = lower;
+       u32 _mid = mid;
+       u32 _upper = upper;
+
+       return _lower | (_mid << 8) | (_upper << 16);
+}
+
+static IIO_SCAN_EL_C(wform, ADE7758_SCAN_WFORM, ADE7758_WFORM, NULL);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(wform, s, 24, 32);
+static IIO_SCAN_EL_TIMESTAMP(1);
+static IIO_CONST_ATTR_SCAN_EL_TYPE(timestamp, s, 64, 64);
+
+static struct attribute *ade7758_scan_el_attrs[] = {
+       &iio_scan_el_wform.dev_attr.attr,
+       &iio_const_attr_wform_index.dev_attr.attr,
+       &iio_const_attr_wform_type.dev_attr.attr,
+       &iio_scan_el_timestamp.dev_attr.attr,
+       &iio_const_attr_timestamp_index.dev_attr.attr,
+       &iio_const_attr_timestamp_type.dev_attr.attr,
+       NULL,
+};
+
+static struct attribute_group ade7758_scan_el_group = {
+       .attrs = ade7758_scan_el_attrs,
+       .name = "scan_elements",
+};
+
+/**
+ * ade7758_poll_func_th() top half interrupt handler called by trigger
+ * @private_data:      iio_dev
+ **/
+static void ade7758_poll_func_th(struct iio_dev *indio_dev, s64 time)
+{
+       struct ade7758_state *st = iio_dev_get_devdata(indio_dev);
+       st->last_timestamp = time;
+       schedule_work(&st->work_trigger_to_ring);
+       /* Indicate that this interrupt is being handled */
+
+       /* Technically this is trigger related, but without this
+        * handler running there is currently no way for the interrupt
+        * to clear.
+        */
+}
+
+/**
+ * ade7758_spi_read_burst() - read all data registers
+ * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @rx: somewhere to pass back the value read (min size is 24 bytes)
+ **/
+static int ade7758_spi_read_burst(struct device *dev, u8 *rx)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7758_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .rx_buf = rx,
+                       .bits_per_word = 8,
+                       .len = 4,
+               }, {
+                       .tx_buf = st->tx + 4,
+                       .rx_buf = rx,
+                       .bits_per_word = 8,
+                       .len = 4,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7758_READ_REG(ADE7758_RSTATUS);
+       st->tx[1] = 0;
+       st->tx[2] = 0;
+       st->tx[3] = 0;
+       st->tx[4] = ADE7758_READ_REG(ADE7758_WFORM);
+       st->tx[5] = 0;
+       st->tx[6] = 0;
+       st->tx[7] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfers[0], &msg);
+       spi_message_add_tail(&xfers[1], &msg);
+       ret = spi_sync(st->us, &msg);
+       if (ret)
+               dev_err(&st->us->dev, "problem when reading WFORM value\n");
+
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+/* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device
+ * specific to be rolled into the core.
+ */
+static void ade7758_trigger_bh_to_ring(struct work_struct *work_s)
+{
+       struct ade7758_state *st
+               = container_of(work_s, struct ade7758_state,
+                              work_trigger_to_ring);
+       struct iio_ring_buffer *ring = st->indio_dev->ring;
+
+       int i = 0;
+       s32 *data;
+       size_t datasize = ring->access.get_bytes_per_datum(ring);
+
+       data = kmalloc(datasize, GFP_KERNEL);
+       if (data == NULL) {
+               dev_err(&st->us->dev, "memory alloc failed in ring bh");
+               return;
+       }
+
+       if (ring->scan_count)
+               if (ade7758_spi_read_burst(&st->indio_dev->dev, st->rx) >= 0)
+                       for (; i < ring->scan_count; i++)
+                               data[i] = combine_8_to_32(st->rx[i*2+2],
+                                               st->rx[i*2+1],
+                                               st->rx[i*2]);
+
+       /* Guaranteed to be aligned with 8 byte boundary */
+       if (ring->scan_timestamp)
+               *((s64 *)
+               (((u32)data + 4 * ring->scan_count + 4) & ~0x7)) =
+                       st->last_timestamp;
+
+       ring->access.store_to(ring,
+                             (u8 *)data,
+                             st->last_timestamp);
+
+       iio_trigger_notify_done(st->indio_dev->trig);
+       kfree(data);
+
+       return;
+}
+
+void ade7758_unconfigure_ring(struct iio_dev *indio_dev)
+{
+       kfree(indio_dev->pollfunc);
+       iio_sw_rb_free(indio_dev->ring);
+}
+
+int ade7758_configure_ring(struct iio_dev *indio_dev)
+{
+       int ret = 0;
+       struct ade7758_state *st = indio_dev->dev_data;
+       struct iio_ring_buffer *ring;
+       INIT_WORK(&st->work_trigger_to_ring, ade7758_trigger_bh_to_ring);
+
+       ring = iio_sw_rb_allocate(indio_dev);
+       if (!ring) {
+               ret = -ENOMEM;
+               return ret;
+       }
+       indio_dev->ring = ring;
+       /* Effectively select the ring buffer implementation */
+       iio_ring_sw_register_funcs(&ring->access);
+       ring->bpe = 4;
+       ring->scan_el_attrs = &ade7758_scan_el_group;
+       ring->scan_timestamp = true;
+       ring->preenable = &iio_sw_ring_preenable;
+       ring->postenable = &iio_triggered_ring_postenable;
+       ring->predisable = &iio_triggered_ring_predisable;
+       ring->owner = THIS_MODULE;
+
+       /* Set default scan mode */
+       iio_scan_mask_set(ring, iio_scan_el_wform.number);
+
+       ret = iio_alloc_pollfunc(indio_dev, NULL, &ade7758_poll_func_th);
+       if (ret)
+               goto error_iio_sw_rb_free;
+
+       indio_dev->modes |= INDIO_RING_TRIGGERED;
+       return 0;
+
+error_iio_sw_rb_free:
+       iio_sw_rb_free(indio_dev->ring);
+       return ret;
+}
+
+int ade7758_initialize_ring(struct iio_ring_buffer *ring)
+{
+       return iio_ring_buffer_register(ring, 0);
+}
+
+void ade7758_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+       iio_ring_buffer_unregister(ring);
+}
diff --git a/drivers/staging/iio/meter/ade7758_trigger.c b/drivers/staging/iio/meter/ade7758_trigger.c
new file mode 100644 (file)
index 0000000..60abca0
--- /dev/null
@@ -0,0 +1,125 @@
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/spi/spi.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "../trigger.h"
+#include "ade7758.h"
+
+/**
+ * ade7758_data_rdy_trig_poll() the event handler for the data rdy trig
+ **/
+static int ade7758_data_rdy_trig_poll(struct iio_dev *dev_info,
+                                      int index,
+                                      s64 timestamp,
+                                      int no_test)
+{
+       struct ade7758_state *st = iio_dev_get_devdata(dev_info);
+       struct iio_trigger *trig = st->trig;
+
+       iio_trigger_poll(trig, timestamp);
+
+       return IRQ_HANDLED;
+}
+
+IIO_EVENT_SH(data_rdy_trig, &ade7758_data_rdy_trig_poll);
+
+static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL);
+
+static struct attribute *ade7758_trigger_attrs[] = {
+       &dev_attr_name.attr,
+       NULL,
+};
+
+static const struct attribute_group ade7758_trigger_attr_group = {
+       .attrs = ade7758_trigger_attrs,
+};
+
+/**
+ * ade7758_data_rdy_trigger_set_state() set datardy interrupt state
+ **/
+static int ade7758_data_rdy_trigger_set_state(struct iio_trigger *trig,
+                                               bool state)
+{
+       struct ade7758_state *st = trig->private_data;
+       struct iio_dev *indio_dev = st->indio_dev;
+       int ret = 0;
+
+       dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state);
+       ret = ade7758_set_irq(&st->indio_dev->dev, state);
+       if (state == false) {
+               iio_remove_event_from_list(&iio_event_data_rdy_trig,
+                                          &indio_dev->interrupts[0]
+                                          ->ev_list);
+               /* possible quirk with handler currently worked around
+                  by ensuring the work queue is empty */
+               flush_scheduled_work();
+       } else {
+               iio_add_event_to_list(&iio_event_data_rdy_trig,
+                                     &indio_dev->interrupts[0]->ev_list);
+       }
+       return ret;
+}
+
+/**
+ * ade7758_trig_try_reen() try renabling irq for data rdy trigger
+ * @trig:      the datardy trigger
+ **/
+static int ade7758_trig_try_reen(struct iio_trigger *trig)
+{
+       struct ade7758_state *st = trig->private_data;
+       enable_irq(st->us->irq);
+       /* irq reenabled so success! */
+       return 0;
+}
+
+int ade7758_probe_trigger(struct iio_dev *indio_dev)
+{
+       int ret;
+       struct ade7758_state *st = indio_dev->dev_data;
+
+       st->trig = iio_allocate_trigger();
+       st->trig->name = kasprintf(GFP_KERNEL,
+                               "ade7758-dev%d",
+                               indio_dev->id);
+       if (!st->trig->name) {
+               ret = -ENOMEM;
+               goto error_free_trig;
+       }
+       st->trig->dev.parent = &st->us->dev;
+       st->trig->owner = THIS_MODULE;
+       st->trig->private_data = st;
+       st->trig->set_trigger_state = &ade7758_data_rdy_trigger_set_state;
+       st->trig->try_reenable = &ade7758_trig_try_reen;
+       st->trig->control_attrs = &ade7758_trigger_attr_group;
+       ret = iio_trigger_register(st->trig);
+
+       /* select default trigger */
+       indio_dev->trig = st->trig;
+       if (ret)
+               goto error_free_trig_name;
+
+       return 0;
+
+error_free_trig_name:
+       kfree(st->trig->name);
+error_free_trig:
+       iio_free_trigger(st->trig);
+
+       return ret;
+}
+
+void ade7758_remove_trigger(struct iio_dev *indio_dev)
+{
+       struct ade7758_state *state = indio_dev->dev_data;
+
+       iio_trigger_unregister(state->trig);
+       kfree(state->trig->name);
+       iio_free_trigger(state->trig);
+}
diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c
new file mode 100644 (file)
index 0000000..fafc3c1
--- /dev/null
@@ -0,0 +1,670 @@
+/*
+ * ADE7759 Active Energy Metering IC with di/dt Sensor Interface Driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "meter.h"
+#include "ade7759.h"
+
+int ade7759_spi_write_reg_8(struct device *dev,
+               u8 reg_address,
+               u8 val)
+{
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7759_state *st = iio_dev_get_devdata(indio_dev);
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7759_WRITE_REG(reg_address);
+       st->tx[1] = val;
+
+       ret = spi_write(st->us, st->tx, 2);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static int ade7759_spi_write_reg_16(struct device *dev,
+               u8 reg_address,
+               u16 value)
+{
+       int ret;
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7759_state *st = iio_dev_get_devdata(indio_dev);
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 3,
+               }
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7759_WRITE_REG(reg_address);
+       st->tx[1] = (value >> 8) & 0xFF;
+       st->tx[2] = value & 0xFF;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->us, &msg);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static int ade7759_spi_read_reg_8(struct device *dev,
+               u8 reg_address,
+               u8 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7759_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .rx_buf = st->rx,
+                       .bits_per_word = 8,
+                       .len = 2,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7759_READ_REG(reg_address);
+       st->tx[1] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->us, &msg);
+       if (ret) {
+               dev_err(&st->us->dev, "problem when reading 8 bit register 0x%02X",
+                               reg_address);
+               goto error_ret;
+       }
+       *val = st->rx[1];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static int ade7759_spi_read_reg_16(struct device *dev,
+               u8 reg_address,
+               u16 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7759_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .rx_buf = st->rx,
+                       .bits_per_word = 8,
+                       .len = 3,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7759_READ_REG(reg_address);
+       st->tx[1] = 0;
+       st->tx[2] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->us, &msg);
+       if (ret) {
+               dev_err(&st->us->dev, "problem when reading 16 bit register 0x%02X",
+                               reg_address);
+               goto error_ret;
+       }
+       *val = (st->rx[1] << 8) | st->rx[2];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static int ade7759_spi_read_reg_40(struct device *dev,
+               u8 reg_address,
+               u64 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7759_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .rx_buf = st->rx,
+                       .bits_per_word = 8,
+                       .len = 6,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7759_READ_REG(reg_address);
+       memset(&st->tx[1], 0 , 5);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->us, &msg);
+       if (ret) {
+               dev_err(&st->us->dev, "problem when reading 40 bit register 0x%02X",
+                               reg_address);
+               goto error_ret;
+       }
+       *val = ((u64)st->rx[1] << 32) | (st->rx[2] << 24) |
+               (st->rx[3] << 16) | (st->rx[4] << 8) | st->rx[5];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static ssize_t ade7759_read_8bit(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u8 val = 0;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = ade7759_spi_read_reg_8(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7759_read_16bit(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u16 val = 0;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = ade7759_spi_read_reg_16(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7759_read_40bit(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u64 val = 0;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = ade7759_spi_read_reg_40(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%llu\n", val);
+}
+
+static ssize_t ade7759_write_8bit(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       int ret;
+       long val;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               goto error_ret;
+       ret = ade7759_spi_write_reg_8(dev, this_attr->address, val);
+
+error_ret:
+       return ret ? ret : len;
+}
+
+static ssize_t ade7759_write_16bit(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       int ret;
+       long val;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               goto error_ret;
+       ret = ade7759_spi_write_reg_16(dev, this_attr->address, val);
+
+error_ret:
+       return ret ? ret : len;
+}
+
+static int ade7759_reset(struct device *dev)
+{
+       int ret;
+       u16 val;
+       ade7759_spi_read_reg_16(dev,
+                       ADE7759_MODE,
+                       &val);
+       val |= 1 << 6; /* Software Chip Reset */
+       ret = ade7759_spi_write_reg_16(dev,
+                       ADE7759_MODE,
+                       val);
+
+       return ret;
+}
+
+static ssize_t ade7759_write_reset(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf, size_t len)
+{
+       if (len < 1)
+               return -1;
+       switch (buf[0]) {
+       case '1':
+       case 'y':
+       case 'Y':
+               return ade7759_reset(dev);
+       }
+       return -1;
+}
+
+static IIO_DEV_ATTR_AENERGY(ade7759_read_40bit, ADE7759_AENERGY);
+static IIO_DEV_ATTR_CFDEN(S_IWUSR | S_IRUGO,
+               ade7759_read_16bit,
+               ade7759_write_16bit,
+               ADE7759_CFDEN);
+static IIO_DEV_ATTR_CFNUM(S_IWUSR | S_IRUGO,
+               ade7759_read_8bit,
+               ade7759_write_8bit,
+               ADE7759_CFNUM);
+static IIO_DEV_ATTR_CHKSUM(ade7759_read_8bit, ADE7759_CHKSUM);
+static IIO_DEV_ATTR_PHCAL(S_IWUSR | S_IRUGO,
+               ade7759_read_16bit,
+               ade7759_write_16bit,
+               ADE7759_PHCAL);
+static IIO_DEV_ATTR_APOS(S_IWUSR | S_IRUGO,
+               ade7759_read_16bit,
+               ade7759_write_16bit,
+               ADE7759_APOS);
+static IIO_DEV_ATTR_SAGCYC(S_IWUSR | S_IRUGO,
+               ade7759_read_8bit,
+               ade7759_write_8bit,
+               ADE7759_SAGCYC);
+static IIO_DEV_ATTR_SAGLVL(S_IWUSR | S_IRUGO,
+               ade7759_read_8bit,
+               ade7759_write_8bit,
+               ADE7759_SAGLVL);
+static IIO_DEV_ATTR_LINECYC(S_IWUSR | S_IRUGO,
+               ade7759_read_8bit,
+               ade7759_write_8bit,
+               ADE7759_LINECYC);
+static IIO_DEV_ATTR_LENERGY(ade7759_read_40bit, ADE7759_LENERGY);
+static IIO_DEV_ATTR_PGA_GAIN(S_IWUSR | S_IRUGO,
+               ade7759_read_8bit,
+               ade7759_write_8bit,
+               ADE7759_GAIN);
+static IIO_DEV_ATTR_ACTIVE_POWER_GAIN(S_IWUSR | S_IRUGO,
+               ade7759_read_16bit,
+               ade7759_write_16bit,
+               ADE7759_APGAIN);
+static IIO_DEV_ATTR_CH_OFF(1, S_IWUSR | S_IRUGO,
+               ade7759_read_8bit,
+               ade7759_write_8bit,
+               ADE7759_CH1OS);
+static IIO_DEV_ATTR_CH_OFF(2, S_IWUSR | S_IRUGO,
+               ade7759_read_8bit,
+               ade7759_write_8bit,
+               ADE7759_CH2OS);
+
+static int ade7759_set_irq(struct device *dev, bool enable)
+{
+       int ret;
+       u8 irqen;
+       ret = ade7759_spi_read_reg_8(dev, ADE7759_IRQEN, &irqen);
+       if (ret)
+               goto error_ret;
+
+       if (enable)
+               irqen |= 1 << 3; /* Enables an interrupt when a data is
+                                   present in the waveform register */
+       else
+               irqen &= ~(1 << 3);
+
+       ret = ade7759_spi_write_reg_8(dev, ADE7759_IRQEN, irqen);
+       if (ret)
+               goto error_ret;
+
+error_ret:
+       return ret;
+}
+
+/* Power down the device */
+int ade7759_stop_device(struct device *dev)
+{
+       int ret;
+       u16 val;
+       ade7759_spi_read_reg_16(dev,
+                       ADE7759_MODE,
+                       &val);
+       val |= 1 << 4;  /* AD converters can be turned off */
+       ret = ade7759_spi_write_reg_16(dev,
+                       ADE7759_MODE,
+                       val);
+
+       return ret;
+}
+
+static int ade7759_initial_setup(struct ade7759_state *st)
+{
+       int ret;
+       struct device *dev = &st->indio_dev->dev;
+
+       /* use low spi speed for init */
+       st->us->mode = SPI_MODE_3;
+       spi_setup(st->us);
+
+       /* Disable IRQ */
+       ret = ade7759_set_irq(dev, false);
+       if (ret) {
+               dev_err(dev, "disable irq failed");
+               goto err_ret;
+       }
+
+       ade7759_reset(dev);
+       msleep(ADE7759_STARTUP_DELAY);
+
+err_ret:
+       return ret;
+}
+
+static ssize_t ade7759_read_frequency(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret, len = 0;
+       u16 t;
+       int sps;
+       ret = ade7759_spi_read_reg_16(dev,
+                       ADE7759_MODE,
+                       &t);
+       if (ret)
+               return ret;
+
+       t = (t >> 3) & 0x3;
+       sps = 27900 / (1 + t);
+
+       len = sprintf(buf, "%d SPS\n", sps);
+       return len;
+}
+
+static ssize_t ade7759_write_frequency(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7759_state *st = iio_dev_get_devdata(indio_dev);
+       unsigned long val;
+       int ret;
+       u16 reg, t;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               return ret;
+
+       mutex_lock(&indio_dev->mlock);
+
+       t = (27900 / val);
+       if (t > 0)
+               t--;
+
+       if (t > 1)
+               st->us->max_speed_hz = ADE7759_SPI_SLOW;
+       else
+               st->us->max_speed_hz = ADE7759_SPI_FAST;
+
+       ret = ade7759_spi_read_reg_16(dev,
+                       ADE7759_MODE,
+                       &reg);
+       if (ret)
+               goto out;
+
+       reg &= ~(3 << 13);
+       reg |= t << 13;
+
+       ret = ade7759_spi_write_reg_16(dev,
+                       ADE7759_MODE,
+                       reg);
+
+out:
+       mutex_unlock(&indio_dev->mlock);
+
+       return ret ? ret : len;
+}
+static IIO_DEV_ATTR_TEMP_RAW(ade7759_read_8bit);
+static IIO_CONST_ATTR(temp_offset, "70 C");
+static IIO_CONST_ATTR(temp_scale, "1 C");
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+               ade7759_read_frequency,
+               ade7759_write_frequency);
+
+static IIO_DEV_ATTR_RESET(ade7759_write_reset);
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("27900 14000 7000 3500");
+
+static IIO_CONST_ATTR(name, "ade7759");
+
+static struct attribute *ade7759_event_attributes[] = {
+       NULL
+};
+
+static struct attribute_group ade7759_event_attribute_group = {
+       .attrs = ade7759_event_attributes,
+};
+
+static struct attribute *ade7759_attributes[] = {
+       &iio_dev_attr_temp_raw.dev_attr.attr,
+       &iio_const_attr_temp_offset.dev_attr.attr,
+       &iio_const_attr_temp_scale.dev_attr.attr,
+       &iio_dev_attr_sampling_frequency.dev_attr.attr,
+       &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+       &iio_dev_attr_reset.dev_attr.attr,
+       &iio_const_attr_name.dev_attr.attr,
+       &iio_dev_attr_phcal.dev_attr.attr,
+       &iio_dev_attr_cfden.dev_attr.attr,
+       &iio_dev_attr_aenergy.dev_attr.attr,
+       &iio_dev_attr_cfnum.dev_attr.attr,
+       &iio_dev_attr_apos.dev_attr.attr,
+       &iio_dev_attr_sagcyc.dev_attr.attr,
+       &iio_dev_attr_saglvl.dev_attr.attr,
+       &iio_dev_attr_linecyc.dev_attr.attr,
+       &iio_dev_attr_lenergy.dev_attr.attr,
+       &iio_dev_attr_chksum.dev_attr.attr,
+       &iio_dev_attr_pga_gain.dev_attr.attr,
+       &iio_dev_attr_active_power_gain.dev_attr.attr,
+       &iio_dev_attr_choff_1.dev_attr.attr,
+       &iio_dev_attr_choff_2.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ade7759_attribute_group = {
+       .attrs = ade7759_attributes,
+};
+
+static int __devinit ade7759_probe(struct spi_device *spi)
+{
+       int ret, regdone = 0;
+       struct ade7759_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+       if (!st) {
+               ret =  -ENOMEM;
+               goto error_ret;
+       }
+       /* this is only used for removal purposes */
+       spi_set_drvdata(spi, st);
+
+       /* Allocate the comms buffers */
+       st->rx = kzalloc(sizeof(*st->rx)*ADE7759_MAX_RX, GFP_KERNEL);
+       if (st->rx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->tx = kzalloc(sizeof(*st->tx)*ADE7759_MAX_TX, GFP_KERNEL);
+       if (st->tx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_rx;
+       }
+       st->us = spi;
+       mutex_init(&st->buf_lock);
+       /* setup the industrialio driver allocated elements */
+       st->indio_dev = iio_allocate_device();
+       if (st->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_tx;
+       }
+
+       st->indio_dev->dev.parent = &spi->dev;
+       st->indio_dev->num_interrupt_lines = 1;
+       st->indio_dev->event_attrs = &ade7759_event_attribute_group;
+       st->indio_dev->attrs = &ade7759_attribute_group;
+       st->indio_dev->dev_data = (void *)(st);
+       st->indio_dev->driver_module = THIS_MODULE;
+       st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = ade7759_configure_ring(st->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       ret = iio_device_register(st->indio_dev);
+       if (ret)
+               goto error_unreg_ring_funcs;
+       regdone = 1;
+
+       ret = ade7759_initialize_ring(st->indio_dev->ring);
+       if (ret) {
+               printk(KERN_ERR "failed to initialize the ring\n");
+               goto error_unreg_ring_funcs;
+       }
+
+       if (spi->irq) {
+               ret = iio_register_interrupt_line(spi->irq,
+                               st->indio_dev,
+                               0,
+                               IRQF_TRIGGER_FALLING,
+                               "ade7759");
+               if (ret)
+                       goto error_uninitialize_ring;
+
+               ret = ade7759_probe_trigger(st->indio_dev);
+               if (ret)
+                       goto error_unregister_line;
+       }
+
+       /* Get the device into a sane initial state */
+       ret = ade7759_initial_setup(st);
+       if (ret)
+               goto error_remove_trigger;
+       return 0;
+
+error_remove_trigger:
+       if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+               ade7759_remove_trigger(st->indio_dev);
+error_unregister_line:
+       if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+               iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+       ade7759_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+       ade7759_unconfigure_ring(st->indio_dev);
+error_free_dev:
+       if (regdone)
+               iio_device_unregister(st->indio_dev);
+       else
+               iio_free_device(st->indio_dev);
+error_free_tx:
+       kfree(st->tx);
+error_free_rx:
+       kfree(st->rx);
+error_free_st:
+       kfree(st);
+error_ret:
+       return ret;
+}
+
+/* fixme, confirm ordering in this function */
+static int ade7759_remove(struct spi_device *spi)
+{
+       int ret;
+       struct ade7759_state *st = spi_get_drvdata(spi);
+       struct iio_dev *indio_dev = st->indio_dev;
+
+       ret = ade7759_stop_device(&(indio_dev->dev));
+       if (ret)
+               goto err_ret;
+
+       flush_scheduled_work();
+
+       ade7759_remove_trigger(indio_dev);
+       if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
+               iio_unregister_interrupt_line(indio_dev, 0);
+
+       ade7759_uninitialize_ring(indio_dev->ring);
+       ade7759_unconfigure_ring(indio_dev);
+       iio_device_unregister(indio_dev);
+       kfree(st->tx);
+       kfree(st->rx);
+       kfree(st);
+
+       return 0;
+
+err_ret:
+       return ret;
+}
+
+static struct spi_driver ade7759_driver = {
+       .driver = {
+               .name = "ade7759",
+               .owner = THIS_MODULE,
+       },
+       .probe = ade7759_probe,
+       .remove = __devexit_p(ade7759_remove),
+};
+
+static __init int ade7759_init(void)
+{
+       return spi_register_driver(&ade7759_driver);
+}
+module_init(ade7759_init);
+
+static __exit void ade7759_exit(void)
+{
+       spi_unregister_driver(&ade7759_driver);
+}
+module_exit(ade7759_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADE7759 Active Energy Metering IC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/meter/ade7759.h b/drivers/staging/iio/meter/ade7759.h
new file mode 100644 (file)
index 0000000..813dea2
--- /dev/null
@@ -0,0 +1,122 @@
+#ifndef _ADE7759_H
+#define _ADE7759_H
+
+#define ADE7759_WAVEFORM  0x01
+#define ADE7759_AENERGY   0x02
+#define ADE7759_RSTENERGY 0x03
+#define ADE7759_STATUS    0x04
+#define ADE7759_RSTSTATUS 0x05
+#define ADE7759_MODE      0x06
+#define ADE7759_CFDEN     0x07
+#define ADE7759_CH1OS     0x08
+#define ADE7759_CH2OS     0x09
+#define ADE7759_GAIN      0x0A
+#define ADE7759_APGAIN    0x0B
+#define ADE7759_PHCAL     0x0C
+#define ADE7759_APOS      0x0D
+#define ADE7759_ZXTOUT    0x0E
+#define ADE7759_SAGCYC    0x0F
+#define ADE7759_IRQEN     0x10
+#define ADE7759_SAGLVL    0x11
+#define ADE7759_TEMP      0x12
+#define ADE7759_LINECYC   0x13
+#define ADE7759_LENERGY   0x14
+#define ADE7759_CFNUM     0x15
+#define ADE7759_CHKSUM    0x1E
+#define ADE7759_DIEREV    0x1F
+
+#define ADE7759_READ_REG(a)    a
+#define ADE7759_WRITE_REG(a) ((a) | 0x80)
+
+#define ADE7759_MAX_TX    6
+#define ADE7759_MAX_RX    6
+#define ADE7759_STARTUP_DELAY 1
+
+#define ADE7759_SPI_SLOW       (u32)(300 * 1000)
+#define ADE7759_SPI_BURST      (u32)(1000 * 1000)
+#define ADE7759_SPI_FAST       (u32)(2000 * 1000)
+
+#define DRIVER_NAME            "ade7759"
+
+/**
+ * struct ade7759_state - device instance specific data
+ * @us:                        actual spi_device
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter:             used to check if new interrupt has been triggered
+ * @last_timestamp:    passing timestamp from th to bh of interrupt handler
+ * @indio_dev:         industrial I/O device structure
+ * @trig:              data ready trigger registered with iio
+ * @tx:                        transmit buffer
+ * @rx:                        recieve buffer
+ * @buf_lock:          mutex to protect tx and rx
+ **/
+struct ade7759_state {
+       struct spi_device               *us;
+       struct work_struct              work_trigger_to_ring;
+       s64                             last_timestamp;
+       struct iio_dev                  *indio_dev;
+       struct iio_trigger              *trig;
+       u8                              *tx;
+       u8                              *rx;
+       struct mutex                    buf_lock;
+};
+#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
+
+enum ade7759_scan {
+       ADE7759_SCAN_ACTIVE_POWER,
+       ADE7759_SCAN_CH1_CH2,
+       ADE7759_SCAN_CH1,
+       ADE7759_SCAN_CH2,
+};
+
+void ade7759_remove_trigger(struct iio_dev *indio_dev);
+int ade7759_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t ade7759_read_data_from_ring(struct device *dev,
+               struct device_attribute *attr,
+               char *buf);
+
+
+int ade7759_configure_ring(struct iio_dev *indio_dev);
+void ade7759_unconfigure_ring(struct iio_dev *indio_dev);
+
+int ade7759_initialize_ring(struct iio_ring_buffer *ring);
+void ade7759_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void ade7759_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7759_probe_trigger(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline ssize_t
+ade7759_read_data_from_ring(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       return 0;
+}
+
+static int ade7759_configure_ring(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+static inline void ade7759_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7759_initialize_ring(struct iio_ring_buffer *ring)
+{
+       return 0;
+}
+static inline void ade7759_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+#endif /* CONFIG_IIO_RING_BUFFER */
+
+#endif
diff --git a/drivers/staging/iio/meter/ade7854-i2c.c b/drivers/staging/iio/meter/ade7854-i2c.c
new file mode 100644 (file)
index 0000000..4578e7b
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver (I2C Bus)
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include "../iio.h"
+#include "ade7854.h"
+
+static int ade7854_i2c_write_reg_8(struct device *dev,
+               u16 reg_address,
+               u8 value)
+{
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = (reg_address >> 8) & 0xFF;
+       st->tx[1] = reg_address & 0xFF;
+       st->tx[2] = value;
+
+       ret = i2c_master_send(st->i2c, st->tx, 3);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static int ade7854_i2c_write_reg_16(struct device *dev,
+               u16 reg_address,
+               u16 value)
+{
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = (reg_address >> 8) & 0xFF;
+       st->tx[1] = reg_address & 0xFF;
+       st->tx[2] = (value >> 8) & 0xFF;
+       st->tx[3] = value & 0xFF;
+
+       ret = i2c_master_send(st->i2c, st->tx, 4);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static int ade7854_i2c_write_reg_24(struct device *dev,
+               u16 reg_address,
+               u32 value)
+{
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = (reg_address >> 8) & 0xFF;
+       st->tx[1] = reg_address & 0xFF;
+       st->tx[2] = (value >> 16) & 0xFF;
+       st->tx[3] = (value >> 8) & 0xFF;
+       st->tx[4] = value & 0xFF;
+
+       ret = i2c_master_send(st->i2c, st->tx, 5);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static int ade7854_i2c_write_reg_32(struct device *dev,
+               u16 reg_address,
+               u32 value)
+{
+       int ret;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = (reg_address >> 8) & 0xFF;
+       st->tx[1] = reg_address & 0xFF;
+       st->tx[2] = (value >> 24) & 0xFF;
+       st->tx[3] = (value >> 16) & 0xFF;
+       st->tx[4] = (value >> 8) & 0xFF;
+       st->tx[5] = value & 0xFF;
+
+       ret = i2c_master_send(st->i2c, st->tx, 6);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static int ade7854_i2c_read_reg_8(struct device *dev,
+               u16 reg_address,
+               u8 *val)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = (reg_address >> 8) & 0xFF;
+       st->tx[1] = reg_address & 0xFF;
+
+       ret = i2c_master_send(st->i2c, st->tx, 2);
+       if (ret)
+               goto out;
+
+       ret = i2c_master_recv(st->i2c, st->rx, 1);
+       if (ret)
+               goto out;
+
+       *val = st->rx[0];
+out:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static int ade7854_i2c_read_reg_16(struct device *dev,
+               u16 reg_address,
+               u16 *val)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = (reg_address >> 8) & 0xFF;
+       st->tx[1] = reg_address & 0xFF;
+
+       ret = i2c_master_send(st->i2c, st->tx, 2);
+       if (ret)
+               goto out;
+
+       ret = i2c_master_recv(st->i2c, st->rx, 2);
+       if (ret)
+               goto out;
+
+       *val = (st->rx[0] << 8) | st->rx[1];
+out:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static int ade7854_i2c_read_reg_24(struct device *dev,
+               u16 reg_address,
+               u32 *val)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = (reg_address >> 8) & 0xFF;
+       st->tx[1] = reg_address & 0xFF;
+
+       ret = i2c_master_send(st->i2c, st->tx, 2);
+       if (ret)
+               goto out;
+
+       ret = i2c_master_recv(st->i2c, st->rx, 3);
+       if (ret)
+               goto out;
+
+       *val = (st->rx[0] << 16) | (st->rx[1] << 8) | st->rx[2];
+out:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static int ade7854_i2c_read_reg_32(struct device *dev,
+               u16 reg_address,
+               u32 *val)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = (reg_address >> 8) & 0xFF;
+       st->tx[1] = reg_address & 0xFF;
+
+       ret = i2c_master_send(st->i2c, st->tx, 2);
+       if (ret)
+               goto out;
+
+       ret = i2c_master_recv(st->i2c, st->rx, 3);
+       if (ret)
+               goto out;
+
+       *val = (st->rx[0] << 24) | (st->rx[1] << 16) | (st->rx[2] << 8) | st->rx[3];
+out:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static int __devinit ade7854_i2c_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       int ret;
+       struct ade7854_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+       if (!st) {
+               ret =  -ENOMEM;
+               return ret;
+       }
+
+       i2c_set_clientdata(client, st);
+       st->read_reg_8 = ade7854_i2c_read_reg_8;
+       st->read_reg_16 = ade7854_i2c_read_reg_16;
+       st->read_reg_24 = ade7854_i2c_read_reg_24;
+       st->read_reg_32 = ade7854_i2c_read_reg_32;
+       st->write_reg_8 = ade7854_i2c_write_reg_8;
+       st->write_reg_16 = ade7854_i2c_write_reg_16;
+       st->write_reg_24 = ade7854_i2c_write_reg_24;
+       st->write_reg_32 = ade7854_i2c_write_reg_32;
+       st->i2c = client;
+       st->irq = client->irq;
+
+       ret = ade7854_probe(st, &client->dev);
+       if (ret) {
+               kfree(st);
+               return ret;
+       }
+
+       return ret;
+}
+
+static int __devexit ade7854_i2c_remove(struct i2c_client *client)
+{
+       return ade7854_remove(i2c_get_clientdata(client));
+}
+
+static const struct i2c_device_id ade7854_id[] = {
+       { "ade7854", 0 },
+       { "ade7858", 0 },
+       { "ade7868", 0 },
+       { "ade7878", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ade7854_id);
+
+static struct i2c_driver ade7854_i2c_driver = {
+       .driver = {
+               .name = "ade7854",
+       },
+       .probe    = ade7854_i2c_probe,
+       .remove   = __devexit_p(ade7854_i2c_remove),
+       .id_table = ade7854_id,
+};
+
+static __init int ade7854_i2c_init(void)
+{
+       return i2c_add_driver(&ade7854_i2c_driver);
+}
+module_init(ade7854_i2c_init);
+
+static __exit void ade7854_i2c_exit(void)
+{
+       i2c_del_driver(&ade7854_i2c_driver);
+}
+module_exit(ade7854_i2c_exit);
+
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC I2C Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/meter/ade7854-spi.c b/drivers/staging/iio/meter/ade7854-spi.c
new file mode 100644 (file)
index 0000000..fe58103
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver (SPI Bus)
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+
+#include "../iio.h"
+#include "ade7854.h"
+
+static int ade7854_spi_write_reg_8(struct device *dev,
+               u16 reg_address,
+               u8 value)
+{
+       int ret;
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 4,
+               }
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7854_WRITE_REG;
+       st->tx[1] = (reg_address >> 8) & 0xFF;
+       st->tx[2] = reg_address & 0xFF;
+       st->tx[3] = value & 0xFF;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->spi, &msg);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static int ade7854_spi_write_reg_16(struct device *dev,
+               u16 reg_address,
+               u16 value)
+{
+       int ret;
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 5,
+               }
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7854_WRITE_REG;
+       st->tx[1] = (reg_address >> 8) & 0xFF;
+       st->tx[2] = reg_address & 0xFF;
+       st->tx[3] = (value >> 8) & 0xFF;
+       st->tx[4] = value & 0xFF;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->spi, &msg);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static int ade7854_spi_write_reg_24(struct device *dev,
+               u16 reg_address,
+               u32 value)
+{
+       int ret;
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 6,
+               }
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7854_WRITE_REG;
+       st->tx[1] = (reg_address >> 8) & 0xFF;
+       st->tx[2] = reg_address & 0xFF;
+       st->tx[3] = (value >> 16) & 0xFF;
+       st->tx[4] = (value >> 8) & 0xFF;
+       st->tx[5] = value & 0xFF;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->spi, &msg);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static int ade7854_spi_write_reg_32(struct device *dev,
+               u16 reg_address,
+               u32 value)
+{
+       int ret;
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 7,
+               }
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7854_WRITE_REG;
+       st->tx[1] = (reg_address >> 8) & 0xFF;
+       st->tx[2] = reg_address & 0xFF;
+       st->tx[3] = (value >> 24) & 0xFF;
+       st->tx[4] = (value >> 16) & 0xFF;
+       st->tx[5] = (value >> 8) & 0xFF;
+       st->tx[6] = value & 0xFF;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->spi, &msg);
+       mutex_unlock(&st->buf_lock);
+
+       return ret;
+}
+
+static int ade7854_spi_read_reg_8(struct device *dev,
+               u16 reg_address,
+               u8 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 4,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+
+       st->tx[0] = ADE7854_READ_REG;
+       st->tx[1] = (reg_address >> 8) & 0xFF;
+       st->tx[2] = reg_address & 0xFF;
+       st->tx[3] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->spi, &msg);
+       if (ret) {
+               dev_err(&st->spi->dev, "problem when reading 8 bit register 0x%02X",
+                               reg_address);
+               goto error_ret;
+       }
+       *val = st->rx[3];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static int ade7854_spi_read_reg_16(struct device *dev,
+               u16 reg_address,
+               u16 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 5,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+       st->tx[0] = ADE7854_READ_REG;
+       st->tx[1] = (reg_address >> 8) & 0xFF;
+       st->tx[2] = reg_address & 0xFF;
+       st->tx[3] = 0;
+       st->tx[4] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->spi, &msg);
+       if (ret) {
+               dev_err(&st->spi->dev, "problem when reading 16 bit register 0x%02X",
+                               reg_address);
+               goto error_ret;
+       }
+       *val = (st->rx[3] << 8) | st->rx[4];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static int ade7854_spi_read_reg_24(struct device *dev,
+               u16 reg_address,
+               u32 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 6,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+
+       st->tx[0] = ADE7854_READ_REG;
+       st->tx[1] = (reg_address >> 8) & 0xFF;
+       st->tx[2] = reg_address & 0xFF;
+       st->tx[3] = 0;
+       st->tx[4] = 0;
+       st->tx[5] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->spi, &msg);
+       if (ret) {
+               dev_err(&st->spi->dev, "problem when reading 24 bit register 0x%02X",
+                               reg_address);
+               goto error_ret;
+       }
+       *val = (st->rx[3] << 16) | (st->rx[4] << 8) | st->rx[5];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static int ade7854_spi_read_reg_32(struct device *dev,
+               u16 reg_address,
+               u32 *val)
+{
+       struct spi_message msg;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+       int ret;
+       struct spi_transfer xfers[] = {
+               {
+                       .tx_buf = st->tx,
+                       .bits_per_word = 8,
+                       .len = 7,
+               },
+       };
+
+       mutex_lock(&st->buf_lock);
+
+       st->tx[0] = ADE7854_READ_REG;
+       st->tx[1] = (reg_address >> 8) & 0xFF;
+       st->tx[2] = reg_address & 0xFF;
+       st->tx[3] = 0;
+       st->tx[4] = 0;
+       st->tx[5] = 0;
+       st->tx[6] = 0;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(xfers, &msg);
+       ret = spi_sync(st->spi, &msg);
+       if (ret) {
+               dev_err(&st->spi->dev, "problem when reading 32 bit register 0x%02X",
+                               reg_address);
+               goto error_ret;
+       }
+       *val = (st->rx[3] << 24) | (st->rx[4] << 16) | (st->rx[5] << 8) | st->rx[6];
+
+error_ret:
+       mutex_unlock(&st->buf_lock);
+       return ret;
+}
+
+static int __devinit ade7854_spi_probe(struct spi_device *spi)
+{
+       int ret;
+       struct ade7854_state *st = kzalloc(sizeof *st, GFP_KERNEL);
+       if (!st) {
+               ret =  -ENOMEM;
+               return ret;
+       }
+
+       spi_set_drvdata(spi, st);
+       st->read_reg_8 = ade7854_spi_read_reg_8;
+       st->read_reg_16 = ade7854_spi_read_reg_16;
+       st->read_reg_24 = ade7854_spi_read_reg_24;
+       st->read_reg_32 = ade7854_spi_read_reg_32;
+       st->write_reg_8 = ade7854_spi_write_reg_8;
+       st->write_reg_16 = ade7854_spi_write_reg_16;
+       st->write_reg_24 = ade7854_spi_write_reg_24;
+       st->write_reg_32 = ade7854_spi_write_reg_32;
+       st->irq = spi->irq;
+       st->spi = spi;
+
+       ret = ade7854_probe(st, &spi->dev);
+       if (ret) {
+               kfree(st);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int ade7854_spi_remove(struct spi_device *spi)
+{
+       ade7854_remove(spi_get_drvdata(spi));
+
+       return 0;
+}
+
+static struct spi_driver ade7854_driver = {
+       .driver = {
+               .name = "ade7854",
+               .owner = THIS_MODULE,
+       },
+       .probe = ade7854_spi_probe,
+       .remove = __devexit_p(ade7854_spi_remove),
+};
+
+static __init int ade7854_init(void)
+{
+       return spi_register_driver(&ade7854_driver);
+}
+module_init(ade7854_init);
+
+static __exit void ade7854_exit(void)
+{
+       spi_unregister_driver(&ade7854_driver);
+}
+module_exit(ade7854_exit);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC SPI Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/meter/ade7854.c b/drivers/staging/iio/meter/ade7854.c
new file mode 100644 (file)
index 0000000..a13d504
--- /dev/null
@@ -0,0 +1,680 @@
+/*
+ * ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+#include "meter.h"
+#include "ade7854.h"
+
+static ssize_t ade7854_read_8bit(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u8 val = 0;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = st->read_reg_8(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7854_read_16bit(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u16 val = 0;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = st->read_reg_16(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7854_read_24bit(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u32 val = 0;
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+
+       ret = st->read_reg_24(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%u\n", val & 0xFFFFFF);
+}
+
+static ssize_t ade7854_read_32bit(struct device *dev,
+               struct device_attribute *attr,
+               char *buf)
+{
+       int ret;
+       u32 val = 0;
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+       ret = st->read_reg_32(dev, this_attr->address, &val);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t ade7854_write_8bit(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+       int ret;
+       long val;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               goto error_ret;
+       ret = st->write_reg_8(dev, this_attr->address, val);
+
+error_ret:
+       return ret ? ret : len;
+}
+
+static ssize_t ade7854_write_16bit(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+       int ret;
+       long val;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               goto error_ret;
+       ret = st->write_reg_16(dev, this_attr->address, val);
+
+error_ret:
+       return ret ? ret : len;
+}
+
+static ssize_t ade7854_write_24bit(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+       int ret;
+       long val;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               goto error_ret;
+       ret = st->write_reg_24(dev, this_attr->address, val);
+
+error_ret:
+       return ret ? ret : len;
+}
+
+static ssize_t ade7854_write_32bit(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf,
+               size_t len)
+{
+       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+       int ret;
+       long val;
+
+       ret = strict_strtol(buf, 10, &val);
+       if (ret)
+               goto error_ret;
+       ret = st->write_reg_32(dev, this_attr->address, val);
+
+error_ret:
+       return ret ? ret : len;
+}
+
+static int ade7854_reset(struct device *dev)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+       int ret;
+       u16 val;
+
+       st->read_reg_16(dev, ADE7854_CONFIG, &val);
+       val |= 1 << 7; /* Software Chip Reset */
+       ret = st->write_reg_16(dev, ADE7854_CONFIG, val);
+
+       return ret;
+}
+
+
+static ssize_t ade7854_write_reset(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf, size_t len)
+{
+       if (len < 1)
+               return -1;
+       switch (buf[0]) {
+       case '1':
+       case 'y':
+       case 'Y':
+               return ade7854_reset(dev);
+       }
+       return -1;
+}
+
+static IIO_DEV_ATTR_AIGAIN(S_IWUSR | S_IRUGO,
+               ade7854_read_24bit,
+               ade7854_write_24bit,
+               ADE7854_AIGAIN);
+static IIO_DEV_ATTR_BIGAIN(S_IWUSR | S_IRUGO,
+               ade7854_read_24bit,
+               ade7854_write_24bit,
+               ADE7854_BIGAIN);
+static IIO_DEV_ATTR_CIGAIN(S_IWUSR | S_IRUGO,
+               ade7854_read_24bit,
+               ade7854_write_24bit,
+               ADE7854_CIGAIN);
+static IIO_DEV_ATTR_NIGAIN(S_IWUSR | S_IRUGO,
+               ade7854_read_24bit,
+               ade7854_write_24bit,
+               ADE7854_NIGAIN);
+static IIO_DEV_ATTR_AVGAIN(S_IWUSR | S_IRUGO,
+               ade7854_read_24bit,
+               ade7854_write_24bit,
+               ADE7854_AVGAIN);
+static IIO_DEV_ATTR_BVGAIN(S_IWUSR | S_IRUGO,
+               ade7854_read_24bit,
+               ade7854_write_24bit,
+               ADE7854_BVGAIN);
+static IIO_DEV_ATTR_CVGAIN(S_IWUSR | S_IRUGO,
+               ade7854_read_24bit,
+               ade7854_write_24bit,
+               ADE7854_CVGAIN);
+static IIO_DEV_ATTR_APPARENT_POWER_A_GAIN(S_IWUSR | S_IRUGO,
+               ade7854_read_24bit,
+               ade7854_write_24bit,
+               ADE7854_AVAGAIN);
+static IIO_DEV_ATTR_APPARENT_POWER_B_GAIN(S_IWUSR | S_IRUGO,
+               ade7854_read_24bit,
+               ade7854_write_24bit,
+               ADE7854_BVAGAIN);
+static IIO_DEV_ATTR_APPARENT_POWER_C_GAIN(S_IWUSR | S_IRUGO,
+               ade7854_read_24bit,
+               ade7854_write_24bit,
+               ADE7854_CVAGAIN);
+static IIO_DEV_ATTR_ACTIVE_POWER_A_OFFSET(S_IWUSR | S_IRUGO,
+               ade7854_read_24bit,
+               ade7854_write_24bit,
+               ADE7854_AWATTOS);
+static IIO_DEV_ATTR_ACTIVE_POWER_B_OFFSET(S_IWUSR | S_IRUGO,
+               ade7854_read_24bit,
+               ade7854_write_24bit,
+               ADE7854_BWATTOS);
+static IIO_DEV_ATTR_ACTIVE_POWER_C_OFFSET(S_IWUSR | S_IRUGO,
+               ade7854_read_24bit,
+               ade7854_write_24bit,
+               ADE7854_CWATTOS);
+static IIO_DEV_ATTR_REACTIVE_POWER_A_GAIN(S_IWUSR | S_IRUGO,
+               ade7854_read_24bit,
+               ade7854_write_24bit,
+               ADE7854_AVARGAIN);
+static IIO_DEV_ATTR_REACTIVE_POWER_B_GAIN(S_IWUSR | S_IRUGO,
+               ade7854_read_24bit,
+               ade7854_write_24bit,
+               ADE7854_BVARGAIN);
+static IIO_DEV_ATTR_REACTIVE_POWER_C_GAIN(S_IWUSR | S_IRUGO,
+               ade7854_read_24bit,
+               ade7854_write_24bit,
+               ADE7854_CVARGAIN);
+static IIO_DEV_ATTR_REACTIVE_POWER_A_OFFSET(S_IWUSR | S_IRUGO,
+               ade7854_read_24bit,
+               ade7854_write_24bit,
+               ADE7854_AVAROS);
+static IIO_DEV_ATTR_REACTIVE_POWER_B_OFFSET(S_IWUSR | S_IRUGO,
+               ade7854_read_24bit,
+               ade7854_write_24bit,
+               ADE7854_BVAROS);
+static IIO_DEV_ATTR_REACTIVE_POWER_C_OFFSET(S_IWUSR | S_IRUGO,
+               ade7854_read_24bit,
+               ade7854_write_24bit,
+               ADE7854_CVAROS);
+static IIO_DEV_ATTR_VPEAK(S_IWUSR | S_IRUGO,
+               ade7854_read_32bit,
+               ade7854_write_32bit,
+               ADE7854_VPEAK);
+static IIO_DEV_ATTR_IPEAK(S_IWUSR | S_IRUGO,
+               ade7854_read_32bit,
+               ade7854_write_32bit,
+               ADE7854_VPEAK);
+static IIO_DEV_ATTR_APHCAL(S_IWUSR | S_IRUGO,
+               ade7854_read_16bit,
+               ade7854_write_16bit,
+               ADE7854_APHCAL);
+static IIO_DEV_ATTR_BPHCAL(S_IWUSR | S_IRUGO,
+               ade7854_read_16bit,
+               ade7854_write_16bit,
+               ADE7854_BPHCAL);
+static IIO_DEV_ATTR_CPHCAL(S_IWUSR | S_IRUGO,
+               ade7854_read_16bit,
+               ade7854_write_16bit,
+               ADE7854_CPHCAL);
+static IIO_DEV_ATTR_CF1DEN(S_IWUSR | S_IRUGO,
+               ade7854_read_16bit,
+               ade7854_write_16bit,
+               ADE7854_CF1DEN);
+static IIO_DEV_ATTR_CF2DEN(S_IWUSR | S_IRUGO,
+               ade7854_read_16bit,
+               ade7854_write_16bit,
+               ADE7854_CF2DEN);
+static IIO_DEV_ATTR_CF3DEN(S_IWUSR | S_IRUGO,
+               ade7854_read_16bit,
+               ade7854_write_16bit,
+               ADE7854_CF3DEN);
+static IIO_DEV_ATTR_LINECYC(S_IWUSR | S_IRUGO,
+               ade7854_read_16bit,
+               ade7854_write_16bit,
+               ADE7854_LINECYC);
+static IIO_DEV_ATTR_SAGCYC(S_IWUSR | S_IRUGO,
+               ade7854_read_8bit,
+               ade7854_write_8bit,
+               ADE7854_SAGCYC);
+static IIO_DEV_ATTR_CFCYC(S_IWUSR | S_IRUGO,
+               ade7854_read_8bit,
+               ade7854_write_8bit,
+               ADE7854_CFCYC);
+static IIO_DEV_ATTR_PEAKCYC(S_IWUSR | S_IRUGO,
+               ade7854_read_8bit,
+               ade7854_write_8bit,
+               ADE7854_PEAKCYC);
+static IIO_DEV_ATTR_CHKSUM(ade7854_read_24bit,
+               ADE7854_CHECKSUM);
+static IIO_DEV_ATTR_ANGLE0(ade7854_read_24bit,
+               ADE7854_ANGLE0);
+static IIO_DEV_ATTR_ANGLE1(ade7854_read_24bit,
+               ADE7854_ANGLE1);
+static IIO_DEV_ATTR_ANGLE2(ade7854_read_24bit,
+               ADE7854_ANGLE2);
+static IIO_DEV_ATTR_AIRMS(S_IRUGO,
+               ade7854_read_24bit,
+               NULL,
+               ADE7854_AIRMS);
+static IIO_DEV_ATTR_BIRMS(S_IRUGO,
+               ade7854_read_24bit,
+               NULL,
+               ADE7854_BIRMS);
+static IIO_DEV_ATTR_CIRMS(S_IRUGO,
+               ade7854_read_24bit,
+               NULL,
+               ADE7854_CIRMS);
+static IIO_DEV_ATTR_NIRMS(S_IRUGO,
+               ade7854_read_24bit,
+               NULL,
+               ADE7854_NIRMS);
+static IIO_DEV_ATTR_AVRMS(S_IRUGO,
+               ade7854_read_24bit,
+               NULL,
+               ADE7854_AVRMS);
+static IIO_DEV_ATTR_BVRMS(S_IRUGO,
+               ade7854_read_24bit,
+               NULL,
+               ADE7854_BVRMS);
+static IIO_DEV_ATTR_CVRMS(S_IRUGO,
+               ade7854_read_24bit,
+               NULL,
+               ADE7854_CVRMS);
+static IIO_DEV_ATTR_AIRMSOS(S_IRUGO,
+               ade7854_read_16bit,
+               ade7854_write_16bit,
+               ADE7854_AIRMSOS);
+static IIO_DEV_ATTR_BIRMSOS(S_IRUGO,
+               ade7854_read_16bit,
+               ade7854_write_16bit,
+               ADE7854_BIRMSOS);
+static IIO_DEV_ATTR_CIRMSOS(S_IRUGO,
+               ade7854_read_16bit,
+               ade7854_write_16bit,
+               ADE7854_CIRMSOS);
+static IIO_DEV_ATTR_AVRMSOS(S_IRUGO,
+               ade7854_read_16bit,
+               ade7854_write_16bit,
+               ADE7854_AVRMSOS);
+static IIO_DEV_ATTR_BVRMSOS(S_IRUGO,
+               ade7854_read_16bit,
+               ade7854_write_16bit,
+               ADE7854_BVRMSOS);
+static IIO_DEV_ATTR_CVRMSOS(S_IRUGO,
+               ade7854_read_16bit,
+               ade7854_write_16bit,
+               ADE7854_CVRMSOS);
+static IIO_DEV_ATTR_VOLT_A(ade7854_read_24bit,
+               ADE7854_VAWV);
+static IIO_DEV_ATTR_VOLT_B(ade7854_read_24bit,
+               ADE7854_VBWV);
+static IIO_DEV_ATTR_VOLT_C(ade7854_read_24bit,
+               ADE7854_VCWV);
+static IIO_DEV_ATTR_CURRENT_A(ade7854_read_24bit,
+               ADE7854_IAWV);
+static IIO_DEV_ATTR_CURRENT_B(ade7854_read_24bit,
+               ADE7854_IBWV);
+static IIO_DEV_ATTR_CURRENT_C(ade7854_read_24bit,
+               ADE7854_ICWV);
+static IIO_DEV_ATTR_AWATTHR(ade7854_read_32bit,
+               ADE7854_AWATTHR);
+static IIO_DEV_ATTR_BWATTHR(ade7854_read_32bit,
+               ADE7854_BWATTHR);
+static IIO_DEV_ATTR_CWATTHR(ade7854_read_32bit,
+               ADE7854_CWATTHR);
+static IIO_DEV_ATTR_AFWATTHR(ade7854_read_32bit,
+               ADE7854_AFWATTHR);
+static IIO_DEV_ATTR_BFWATTHR(ade7854_read_32bit,
+               ADE7854_BFWATTHR);
+static IIO_DEV_ATTR_CFWATTHR(ade7854_read_32bit,
+               ADE7854_CFWATTHR);
+static IIO_DEV_ATTR_AVARHR(ade7854_read_32bit,
+               ADE7854_AVARHR);
+static IIO_DEV_ATTR_BVARHR(ade7854_read_32bit,
+               ADE7854_BVARHR);
+static IIO_DEV_ATTR_CVARHR(ade7854_read_32bit,
+               ADE7854_CVARHR);
+static IIO_DEV_ATTR_AVAHR(ade7854_read_32bit,
+               ADE7854_AVAHR);
+static IIO_DEV_ATTR_BVAHR(ade7854_read_32bit,
+               ADE7854_BVAHR);
+static IIO_DEV_ATTR_CVAHR(ade7854_read_32bit,
+               ADE7854_CVAHR);
+
+static int ade7854_set_irq(struct device *dev, bool enable)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct ade7854_state *st = iio_dev_get_devdata(indio_dev);
+
+       int ret;
+       u32 irqen;
+
+       ret = st->read_reg_32(dev, ADE7854_MASK0, &irqen);
+       if (ret)
+               goto error_ret;
+
+       if (enable)
+               irqen |= 1 << 17; /* 1: interrupt enabled when all periodical
+                                    (at 8 kHz rate) DSP computations finish. */
+       else
+               irqen &= ~(1 << 17);
+
+       ret = st->write_reg_32(dev, ADE7854_MASK0, irqen);
+       if (ret)
+               goto error_ret;
+
+error_ret:
+       return ret;
+}
+
+static int ade7854_initial_setup(struct ade7854_state *st)
+{
+       int ret;
+       struct device *dev = &st->indio_dev->dev;
+
+       /* Disable IRQ */
+       ret = ade7854_set_irq(dev, false);
+       if (ret) {
+               dev_err(dev, "disable irq failed");
+               goto err_ret;
+       }
+
+       ade7854_reset(dev);
+       msleep(ADE7854_STARTUP_DELAY);
+
+err_ret:
+       return ret;
+}
+
+static IIO_DEV_ATTR_RESET(ade7854_write_reset);
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("8000");
+
+static IIO_CONST_ATTR(name, "ade7854");
+
+static struct attribute *ade7854_event_attributes[] = {
+       NULL
+};
+
+static struct attribute_group ade7854_event_attribute_group = {
+       .attrs = ade7854_event_attributes,
+};
+
+static struct attribute *ade7854_attributes[] = {
+       &iio_dev_attr_aigain.dev_attr.attr,
+       &iio_dev_attr_bigain.dev_attr.attr,
+       &iio_dev_attr_cigain.dev_attr.attr,
+       &iio_dev_attr_nigain.dev_attr.attr,
+       &iio_dev_attr_avgain.dev_attr.attr,
+       &iio_dev_attr_bvgain.dev_attr.attr,
+       &iio_dev_attr_cvgain.dev_attr.attr,
+       &iio_dev_attr_linecyc.dev_attr.attr,
+       &iio_dev_attr_sagcyc.dev_attr.attr,
+       &iio_dev_attr_cfcyc.dev_attr.attr,
+       &iio_dev_attr_peakcyc.dev_attr.attr,
+       &iio_dev_attr_chksum.dev_attr.attr,
+       &iio_dev_attr_apparent_power_a_gain.dev_attr.attr,
+       &iio_dev_attr_apparent_power_b_gain.dev_attr.attr,
+       &iio_dev_attr_apparent_power_c_gain.dev_attr.attr,
+       &iio_dev_attr_active_power_a_offset.dev_attr.attr,
+       &iio_dev_attr_active_power_b_offset.dev_attr.attr,
+       &iio_dev_attr_active_power_c_offset.dev_attr.attr,
+       &iio_dev_attr_reactive_power_a_gain.dev_attr.attr,
+       &iio_dev_attr_reactive_power_b_gain.dev_attr.attr,
+       &iio_dev_attr_reactive_power_c_gain.dev_attr.attr,
+       &iio_dev_attr_reactive_power_a_offset.dev_attr.attr,
+       &iio_dev_attr_reactive_power_b_offset.dev_attr.attr,
+       &iio_dev_attr_reactive_power_c_offset.dev_attr.attr,
+       &iio_dev_attr_awatthr.dev_attr.attr,
+       &iio_dev_attr_bwatthr.dev_attr.attr,
+       &iio_dev_attr_cwatthr.dev_attr.attr,
+       &iio_dev_attr_afwatthr.dev_attr.attr,
+       &iio_dev_attr_bfwatthr.dev_attr.attr,
+       &iio_dev_attr_cfwatthr.dev_attr.attr,
+       &iio_dev_attr_avarhr.dev_attr.attr,
+       &iio_dev_attr_bvarhr.dev_attr.attr,
+       &iio_dev_attr_cvarhr.dev_attr.attr,
+       &iio_dev_attr_angle0.dev_attr.attr,
+       &iio_dev_attr_angle1.dev_attr.attr,
+       &iio_dev_attr_angle2.dev_attr.attr,
+       &iio_dev_attr_avahr.dev_attr.attr,
+       &iio_dev_attr_bvahr.dev_attr.attr,
+       &iio_dev_attr_cvahr.dev_attr.attr,
+       &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+       &iio_dev_attr_reset.dev_attr.attr,
+       &iio_const_attr_name.dev_attr.attr,
+       &iio_dev_attr_vpeak.dev_attr.attr,
+       &iio_dev_attr_ipeak.dev_attr.attr,
+       &iio_dev_attr_aphcal.dev_attr.attr,
+       &iio_dev_attr_bphcal.dev_attr.attr,
+       &iio_dev_attr_cphcal.dev_attr.attr,
+       &iio_dev_attr_cf1den.dev_attr.attr,
+       &iio_dev_attr_cf2den.dev_attr.attr,
+       &iio_dev_attr_cf3den.dev_attr.attr,
+       &iio_dev_attr_airms.dev_attr.attr,
+       &iio_dev_attr_birms.dev_attr.attr,
+       &iio_dev_attr_cirms.dev_attr.attr,
+       &iio_dev_attr_nirms.dev_attr.attr,
+       &iio_dev_attr_avrms.dev_attr.attr,
+       &iio_dev_attr_bvrms.dev_attr.attr,
+       &iio_dev_attr_cvrms.dev_attr.attr,
+       &iio_dev_attr_airmsos.dev_attr.attr,
+       &iio_dev_attr_birmsos.dev_attr.attr,
+       &iio_dev_attr_cirmsos.dev_attr.attr,
+       &iio_dev_attr_avrmsos.dev_attr.attr,
+       &iio_dev_attr_bvrmsos.dev_attr.attr,
+       &iio_dev_attr_cvrmsos.dev_attr.attr,
+       &iio_dev_attr_volt_a.dev_attr.attr,
+       &iio_dev_attr_volt_b.dev_attr.attr,
+       &iio_dev_attr_volt_c.dev_attr.attr,
+       &iio_dev_attr_current_a.dev_attr.attr,
+       &iio_dev_attr_current_b.dev_attr.attr,
+       &iio_dev_attr_current_c.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ade7854_attribute_group = {
+       .attrs = ade7854_attributes,
+};
+
+int ade7854_probe(struct ade7854_state *st, struct device *dev)
+{
+       int ret, regdone = 0;
+
+       /* Allocate the comms buffers */
+       st->rx = kzalloc(sizeof(*st->rx)*ADE7854_MAX_RX, GFP_KERNEL);
+       if (st->rx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->tx = kzalloc(sizeof(*st->tx)*ADE7854_MAX_TX, GFP_KERNEL);
+       if (st->tx == NULL) {
+               ret = -ENOMEM;
+               goto error_free_rx;
+       }
+       mutex_init(&st->buf_lock);
+       /* setup the industrialio driver allocated elements */
+       st->indio_dev = iio_allocate_device();
+       if (st->indio_dev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_tx;
+       }
+
+       st->indio_dev->dev.parent = dev;
+       st->indio_dev->num_interrupt_lines = 1;
+       st->indio_dev->event_attrs = &ade7854_event_attribute_group;
+       st->indio_dev->attrs = &ade7854_attribute_group;
+       st->indio_dev->dev_data = (void *)(st);
+       st->indio_dev->driver_module = THIS_MODULE;
+       st->indio_dev->modes = INDIO_DIRECT_MODE;
+
+       ret = ade7854_configure_ring(st->indio_dev);
+       if (ret)
+               goto error_free_dev;
+
+       ret = iio_device_register(st->indio_dev);
+       if (ret)
+               goto error_unreg_ring_funcs;
+       regdone = 1;
+
+       ret = ade7854_initialize_ring(st->indio_dev->ring);
+       if (ret) {
+               printk(KERN_ERR "failed to initialize the ring\n");
+               goto error_unreg_ring_funcs;
+       }
+
+       if (st->irq) {
+               ret = iio_register_interrupt_line(st->irq,
+                               st->indio_dev,
+                               0,
+                               IRQF_TRIGGER_FALLING,
+                               "ade7854");
+               if (ret)
+                       goto error_uninitialize_ring;
+
+               ret = ade7854_probe_trigger(st->indio_dev);
+               if (ret)
+                       goto error_unregister_line;
+       }
+       /* Get the device into a sane initial state */
+       ret = ade7854_initial_setup(st);
+       if (ret)
+               goto error_remove_trigger;
+
+       return 0;
+
+error_remove_trigger:
+       if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+               ade7854_remove_trigger(st->indio_dev);
+error_unregister_line:
+       if (st->indio_dev->modes & INDIO_RING_TRIGGERED)
+               iio_unregister_interrupt_line(st->indio_dev, 0);
+error_uninitialize_ring:
+       ade7854_uninitialize_ring(st->indio_dev->ring);
+error_unreg_ring_funcs:
+       ade7854_unconfigure_ring(st->indio_dev);
+error_free_dev:
+       if (regdone)
+               iio_device_unregister(st->indio_dev);
+       else
+               iio_free_device(st->indio_dev);
+error_free_tx:
+       kfree(st->tx);
+error_free_rx:
+       kfree(st->rx);
+error_free_st:
+       kfree(st);
+       return ret;
+
+}
+EXPORT_SYMBOL(ade7854_probe);
+
+int ade7854_remove(struct ade7854_state *st)
+{
+       struct iio_dev *indio_dev = st->indio_dev;
+
+       flush_scheduled_work();
+
+       ade7854_remove_trigger(indio_dev);
+       if (st->irq)
+               iio_unregister_interrupt_line(indio_dev, 0);
+
+       ade7854_uninitialize_ring(indio_dev->ring);
+       ade7854_unconfigure_ring(indio_dev);
+       iio_device_unregister(indio_dev);
+       kfree(st->tx);
+       kfree(st->rx);
+       kfree(st);
+
+       return 0;
+}
+EXPORT_SYMBOL(ade7854_remove);
+
+MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/meter/ade7854.h b/drivers/staging/iio/meter/ade7854.h
new file mode 100644 (file)
index 0000000..47690e5
--- /dev/null
@@ -0,0 +1,245 @@
+#ifndef _ADE7854_H
+#define _ADE7854_H
+
+#define ADE7854_AIGAIN    0x4380
+#define ADE7854_AVGAIN    0x4381
+#define ADE7854_BIGAIN    0x4382
+#define ADE7854_BVGAIN    0x4383
+#define ADE7854_CIGAIN    0x4384
+#define ADE7854_CVGAIN    0x4385
+#define ADE7854_NIGAIN    0x4386
+#define ADE7854_AIRMSOS   0x4387
+#define ADE7854_AVRMSOS   0x4388
+#define ADE7854_BIRMSOS   0x4389
+#define ADE7854_BVRMSOS   0x438A
+#define ADE7854_CIRMSOS   0x438B
+#define ADE7854_CVRMSOS   0x438C
+#define ADE7854_NIRMSOS   0x438D
+#define ADE7854_AVAGAIN   0x438E
+#define ADE7854_BVAGAIN   0x438F
+#define ADE7854_CVAGAIN   0x4390
+#define ADE7854_AWGAIN    0x4391
+#define ADE7854_AWATTOS   0x4392
+#define ADE7854_BWGAIN    0x4393
+#define ADE7854_BWATTOS   0x4394
+#define ADE7854_CWGAIN    0x4395
+#define ADE7854_CWATTOS   0x4396
+#define ADE7854_AVARGAIN  0x4397
+#define ADE7854_AVAROS    0x4398
+#define ADE7854_BVARGAIN  0x4399
+#define ADE7854_BVAROS    0x439A
+#define ADE7854_CVARGAIN  0x439B
+#define ADE7854_CVAROS    0x439C
+#define ADE7854_AFWGAIN   0x439D
+#define ADE7854_AFWATTOS  0x439E
+#define ADE7854_BFWGAIN   0x439F
+#define ADE7854_BFWATTOS  0x43A0
+#define ADE7854_CFWGAIN   0x43A1
+#define ADE7854_CFWATTOS  0x43A2
+#define ADE7854_AFVARGAIN 0x43A3
+#define ADE7854_AFVAROS   0x43A4
+#define ADE7854_BFVARGAIN 0x43A5
+#define ADE7854_BFVAROS   0x43A6
+#define ADE7854_CFVARGAIN 0x43A7
+#define ADE7854_CFVAROS   0x43A8
+#define ADE7854_VATHR1    0x43A9
+#define ADE7854_VATHR0    0x43AA
+#define ADE7854_WTHR1     0x43AB
+#define ADE7854_WTHR0     0x43AC
+#define ADE7854_VARTHR1   0x43AD
+#define ADE7854_VARTHR0   0x43AE
+#define ADE7854_RSV       0x43AF
+#define ADE7854_VANOLOAD  0x43B0
+#define ADE7854_APNOLOAD  0x43B1
+#define ADE7854_VARNOLOAD 0x43B2
+#define ADE7854_VLEVEL    0x43B3
+#define ADE7854_DICOEFF   0x43B5
+#define ADE7854_HPFDIS    0x43B6
+#define ADE7854_ISUMLVL   0x43B8
+#define ADE7854_ISUM      0x43BF
+#define ADE7854_AIRMS     0x43C0
+#define ADE7854_AVRMS     0x43C1
+#define ADE7854_BIRMS     0x43C2
+#define ADE7854_BVRMS     0x43C3
+#define ADE7854_CIRMS     0x43C4
+#define ADE7854_CVRMS     0x43C5
+#define ADE7854_NIRMS     0x43C6
+#define ADE7854_RUN       0xE228
+#define ADE7854_AWATTHR   0xE400
+#define ADE7854_BWATTHR   0xE401
+#define ADE7854_CWATTHR   0xE402
+#define ADE7854_AFWATTHR  0xE403
+#define ADE7854_BFWATTHR  0xE404
+#define ADE7854_CFWATTHR  0xE405
+#define ADE7854_AVARHR    0xE406
+#define ADE7854_BVARHR    0xE407
+#define ADE7854_CVARHR    0xE408
+#define ADE7854_AFVARHR   0xE409
+#define ADE7854_BFVARHR   0xE40A
+#define ADE7854_CFVARHR   0xE40B
+#define ADE7854_AVAHR     0xE40C
+#define ADE7854_BVAHR     0xE40D
+#define ADE7854_CVAHR     0xE40E
+#define ADE7854_IPEAK     0xE500
+#define ADE7854_VPEAK     0xE501
+#define ADE7854_STATUS0   0xE502
+#define ADE7854_STATUS1   0xE503
+#define ADE7854_OILVL     0xE507
+#define ADE7854_OVLVL     0xE508
+#define ADE7854_SAGLVL    0xE509
+#define ADE7854_MASK0     0xE50A
+#define ADE7854_MASK1     0xE50B
+#define ADE7854_IAWV      0xE50C
+#define ADE7854_IBWV      0xE50D
+#define ADE7854_ICWV      0xE50E
+#define ADE7854_VAWV      0xE510
+#define ADE7854_VBWV      0xE511
+#define ADE7854_VCWV      0xE512
+#define ADE7854_AWATT     0xE513
+#define ADE7854_BWATT     0xE514
+#define ADE7854_CWATT     0xE515
+#define ADE7854_AVA       0xE519
+#define ADE7854_BVA       0xE51A
+#define ADE7854_CVA       0xE51B
+#define ADE7854_CHECKSUM  0xE51F
+#define ADE7854_VNOM      0xE520
+#define ADE7854_PHSTATUS  0xE600
+#define ADE7854_ANGLE0    0xE601
+#define ADE7854_ANGLE1    0xE602
+#define ADE7854_ANGLE2    0xE603
+#define ADE7854_PERIOD    0xE607
+#define ADE7854_PHNOLOAD  0xE608
+#define ADE7854_LINECYC   0xE60C
+#define ADE7854_ZXTOUT    0xE60D
+#define ADE7854_COMPMODE  0xE60E
+#define ADE7854_GAIN      0xE60F
+#define ADE7854_CFMODE    0xE610
+#define ADE7854_CF1DEN    0xE611
+#define ADE7854_CF2DEN    0xE612
+#define ADE7854_CF3DEN    0xE613
+#define ADE7854_APHCAL    0xE614
+#define ADE7854_BPHCAL    0xE615
+#define ADE7854_CPHCAL    0xE616
+#define ADE7854_PHSIGN    0xE617
+#define ADE7854_CONFIG    0xE618
+#define ADE7854_MMODE     0xE700
+#define ADE7854_ACCMODE   0xE701
+#define ADE7854_LCYCMODE  0xE702
+#define ADE7854_PEAKCYC   0xE703
+#define ADE7854_SAGCYC    0xE704
+#define ADE7854_CFCYC     0xE705
+#define ADE7854_HSDC_CFG  0xE706
+#define ADE7854_CONFIG2   0xEC01
+
+#define ADE7854_READ_REG   0x1
+#define ADE7854_WRITE_REG  0x0
+
+#define ADE7854_MAX_TX    7
+#define ADE7854_MAX_RX    7
+#define ADE7854_STARTUP_DELAY 1
+
+#define ADE7854_SPI_SLOW       (u32)(300 * 1000)
+#define ADE7854_SPI_BURST      (u32)(1000 * 1000)
+#define ADE7854_SPI_FAST       (u32)(2000 * 1000)
+
+#define DRIVER_NAME            "ade7854"
+
+/**
+ * struct ade7854_state - device instance specific data
+ * @spi:                       actual spi_device
+ * @work_trigger_to_ring: bh for triggered event handling
+ * @inter:             used to check if new interrupt has been triggered
+ * @last_timestamp:    passing timestamp from th to bh of interrupt handler
+ * @indio_dev:         industrial I/O device structure
+ * @trig:              data ready trigger registered with iio
+ * @tx:                        transmit buffer
+ * @rx:                        recieve buffer
+ * @buf_lock:          mutex to protect tx and rx
+ **/
+struct ade7854_state {
+       struct spi_device               *spi;
+       struct i2c_client               *i2c;
+       struct work_struct              work_trigger_to_ring;
+       s64                             last_timestamp;
+       struct iio_dev                  *indio_dev;
+       struct iio_trigger              *trig;
+       u8                              *tx;
+       u8                              *rx;
+       int                             (*read_reg_8) (struct device *, u16, u8 *);
+       int                             (*read_reg_16) (struct device *, u16, u16 *);
+       int                             (*read_reg_24) (struct device *, u16, u32 *);
+       int                             (*read_reg_32) (struct device *, u16, u32 *);
+       int                             (*write_reg_8) (struct device *, u16, u8);
+       int                             (*write_reg_16) (struct device *, u16, u16);
+       int                             (*write_reg_24) (struct device *, u16, u32);
+       int                             (*write_reg_32) (struct device *, u16, u32);
+       int                             irq;
+       struct mutex                    buf_lock;
+};
+
+extern int ade7854_probe(struct ade7854_state *st, struct device *dev);
+extern int ade7854_remove(struct ade7854_state *st);
+
+#if defined(CONFIG_IIO_RING_BUFFER) && defined(THIS_HAS_RING_BUFFER_SUPPORT)
+/* At the moment triggers are only used for ring buffer
+ * filling. This may change!
+ */
+
+enum ade7854_scan {
+       ADE7854_SCAN_PHA_V,
+       ADE7854_SCAN_PHB_V,
+       ADE7854_SCAN_PHC_V,
+       ADE7854_SCAN_PHA_I,
+       ADE7854_SCAN_PHB_I,
+       ADE7854_SCAN_PHC_I,
+};
+
+void ade7854_remove_trigger(struct iio_dev *indio_dev);
+int ade7854_probe_trigger(struct iio_dev *indio_dev);
+
+ssize_t ade7854_read_data_from_ring(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf);
+
+
+int ade7854_configure_ring(struct iio_dev *indio_dev);
+void ade7854_unconfigure_ring(struct iio_dev *indio_dev);
+
+int ade7854_initialize_ring(struct iio_ring_buffer *ring);
+void ade7854_uninitialize_ring(struct iio_ring_buffer *ring);
+#else /* CONFIG_IIO_RING_BUFFER */
+
+static inline void ade7854_remove_trigger(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7854_probe_trigger(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline ssize_t
+ade7854_read_data_from_ring(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       return 0;
+}
+
+static inline int ade7854_configure_ring(struct iio_dev *indio_dev)
+{
+       return 0;
+}
+
+static inline void ade7854_unconfigure_ring(struct iio_dev *indio_dev)
+{
+}
+static inline int ade7854_initialize_ring(struct iio_ring_buffer *ring)
+{
+       return 0;
+}
+static inline void ade7854_uninitialize_ring(struct iio_ring_buffer *ring)
+{
+}
+#endif /* CONFIG_IIO_RING_BUFFER */
+
+#endif
diff --git a/drivers/staging/iio/meter/meter.h b/drivers/staging/iio/meter/meter.h
new file mode 100644 (file)
index 0000000..142c50d
--- /dev/null
@@ -0,0 +1,396 @@
+#include "../sysfs.h"
+
+/* metering ic types of attribute */
+
+#define IIO_DEV_ATTR_CURRENT_A_OFFSET(_mode, _show, _store, _addr)     \
+       IIO_DEVICE_ATTR(current_a_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CURRENT_B_OFFSET(_mode, _show, _store, _addr)     \
+       IIO_DEVICE_ATTR(current_b_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CURRENT_C_OFFSET(_mode, _show, _store, _addr)     \
+       IIO_DEVICE_ATTR(current_c_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VOLT_A_OFFSET(_mode, _show, _store, _addr)      \
+       IIO_DEVICE_ATTR(volt_a_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VOLT_B_OFFSET(_mode, _show, _store, _addr)      \
+       IIO_DEVICE_ATTR(volt_b_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VOLT_C_OFFSET(_mode, _show, _store, _addr)      \
+       IIO_DEVICE_ATTR(volt_c_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_REACTIVE_POWER_A_OFFSET(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(reactive_power_a_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_REACTIVE_POWER_B_OFFSET(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(reactive_power_b_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_REACTIVE_POWER_C_OFFSET(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(reactive_power_c_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_ACTIVE_POWER_A_OFFSET(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(active_power_a_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_ACTIVE_POWER_B_OFFSET(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(active_power_b_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_ACTIVE_POWER_C_OFFSET(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(active_power_c_offset, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CURRENT_A_GAIN(_mode, _show, _store, _addr)               \
+       IIO_DEVICE_ATTR(current_a_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CURRENT_B_GAIN(_mode, _show, _store, _addr)               \
+       IIO_DEVICE_ATTR(current_b_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CURRENT_C_GAIN(_mode, _show, _store, _addr)               \
+       IIO_DEVICE_ATTR(current_c_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_APPARENT_POWER_A_GAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(apparent_power_a_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_APPARENT_POWER_B_GAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(apparent_power_b_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_APPARENT_POWER_C_GAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(apparent_power_c_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_ACTIVE_POWER_GAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(active_power_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_ACTIVE_POWER_A_GAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(active_power_a_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_ACTIVE_POWER_B_GAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(active_power_b_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_ACTIVE_POWER_C_GAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(active_power_c_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_REACTIVE_POWER_A_GAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(reactive_power_a_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_REACTIVE_POWER_B_GAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(reactive_power_b_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_REACTIVE_POWER_C_GAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(reactive_power_c_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CURRENT_A(_show, _addr)                   \
+       IIO_DEVICE_ATTR(current_a, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_CURRENT_B(_show, _addr)                   \
+       IIO_DEVICE_ATTR(current_b, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_CURRENT_C(_show, _addr)                   \
+       IIO_DEVICE_ATTR(current_c, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_VOLT_A(_show, _addr)                      \
+       IIO_DEVICE_ATTR(volt_a, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_VOLT_B(_show, _addr)                      \
+       IIO_DEVICE_ATTR(volt_b, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_VOLT_C(_show, _addr)                      \
+       IIO_DEVICE_ATTR(volt_c, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_AENERGY(_show, _addr)                     \
+       IIO_DEVICE_ATTR(aenergy, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_LENERGY(_show, _addr)                     \
+       IIO_DEVICE_ATTR(lenergy, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_RAENERGY(_show, _addr)                    \
+       IIO_DEVICE_ATTR(raenergy, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_LAENERGY(_show, _addr)                    \
+       IIO_DEVICE_ATTR(laenergy, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_VAENERGY(_show, _addr)                    \
+       IIO_DEVICE_ATTR(vaenergy, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_LVAENERGY(_show, _addr)                   \
+       IIO_DEVICE_ATTR(lvaenergy, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_RVAENERGY(_show, _addr)                   \
+       IIO_DEVICE_ATTR(rvaenergy, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_LVARENERGY(_show, _addr)                  \
+       IIO_DEVICE_ATTR(lvarenergy, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_CHKSUM(_show, _addr)                       \
+       IIO_DEVICE_ATTR(chksum, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ANGLE0(_show, _addr)                       \
+       IIO_DEVICE_ATTR(angle0, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ANGLE1(_show, _addr)                       \
+       IIO_DEVICE_ATTR(angle1, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_ANGLE2(_show, _addr)                       \
+       IIO_DEVICE_ATTR(angle2, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_AWATTHR(_show, _addr)                     \
+       IIO_DEVICE_ATTR(awatthr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_BWATTHR(_show, _addr)                     \
+       IIO_DEVICE_ATTR(bwatthr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_CWATTHR(_show, _addr)                     \
+       IIO_DEVICE_ATTR(cwatthr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_AFWATTHR(_show, _addr)                    \
+       IIO_DEVICE_ATTR(afwatthr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_BFWATTHR(_show, _addr)                    \
+       IIO_DEVICE_ATTR(bfwatthr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_CFWATTHR(_show, _addr)                    \
+       IIO_DEVICE_ATTR(cfwatthr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_AVARHR(_show, _addr)                      \
+       IIO_DEVICE_ATTR(avarhr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_BVARHR(_show, _addr)                      \
+       IIO_DEVICE_ATTR(bvarhr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_CVARHR(_show, _addr)                      \
+       IIO_DEVICE_ATTR(cvarhr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_AVAHR(_show, _addr)                       \
+       IIO_DEVICE_ATTR(avahr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_BVAHR(_show, _addr)                       \
+       IIO_DEVICE_ATTR(bvahr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_CVAHR(_show, _addr)                       \
+       IIO_DEVICE_ATTR(cvahr, S_IRUGO, _show, NULL, _addr)
+
+#define IIO_DEV_ATTR_IOS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(ios, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VOS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(vos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_PHCAL(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(phcal, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_APHCAL(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(aphcal, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_BPHCAL(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(bphcal, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CPHCAL(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(cphcal, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_APOS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(apos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_AAPOS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(aapos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_BAPOS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(bapos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CAPOS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(capos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_AVRMSGAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(avrmsgain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_BVRMSGAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(bvrmsgain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CVRMSGAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(cvrmsgain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_AIGAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(aigain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_BIGAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(bigain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CIGAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(cigain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_NIGAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(nigain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_AVGAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(avgain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_BVGAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(bvgain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CVGAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(cvgain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_WGAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(wgain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_WDIV(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(wdiv, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CFNUM(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(cfnum, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CFDEN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(cfden, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CF1DEN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(cf1den, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CF2DEN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(cf2den, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CF3DEN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(cf3den, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_IRMS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(irms, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VRMS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(vrms, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_AIRMS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(airms, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_BIRMS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(birms, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CIRMS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(cirms, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_NIRMS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(nirms, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_AVRMS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(avrms, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_BVRMS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(bvrms, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CVRMS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(cvrms, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_IRMSOS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(irmsos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VRMSOS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(vrmsos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_AIRMSOS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(airmsos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_BIRMSOS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(birmsos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CIRMSOS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(cirmsos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_AVRMSOS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(avrmsos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_BVRMSOS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(bvrmsos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CVRMSOS(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(cvrmsos, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VAGAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(vagain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_PGA_GAIN(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(pga_gain, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VADIV(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(vadiv, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_LINECYC(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(linecyc, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_SAGCYC(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(sagcyc, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CFCYC(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(cfcyc, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_PEAKCYC(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(peakcyc, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_SAGLVL(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(saglvl, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_IPKLVL(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(ipklvl, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VPKLVL(_mode, _show, _store, _addr)                \
+       IIO_DEVICE_ATTR(vpklvl, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_IPEAK(_mode, _show, _store, _addr)                        \
+       IIO_DEVICE_ATTR(ipeak, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_RIPEAK(_mode, _show, _store, _addr)                       \
+       IIO_DEVICE_ATTR(ripeak, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VPEAK(_mode, _show, _store, _addr)                        \
+       IIO_DEVICE_ATTR(vpeak, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_RVPEAK(_mode, _show, _store, _addr)                       \
+       IIO_DEVICE_ATTR(rvpeak, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_VPERIOD(_mode, _show, _store, _addr)                      \
+       IIO_DEVICE_ATTR(vperiod, _mode, _show, _store, _addr)
+
+#define IIO_DEV_ATTR_CH_OFF(_num, _mode, _show, _store, _addr)                 \
+  IIO_DEVICE_ATTR(choff_##_num, _mode, _show, _store, _addr)
+
+/* active energy register, AENERGY, is more than half full */
+#define IIO_EVENT_ATTR_AENERGY_HALF_FULL(_evlist, _show, _store, _mask) \
+       IIO_EVENT_ATTR_SH(aenergy_half_full, _evlist, _show, _store, _mask)
+
+/* a SAG on the line voltage */
+#define IIO_EVENT_ATTR_LINE_VOLT_SAG(_evlist, _show, _store, _mask) \
+       IIO_EVENT_ATTR_SH(line_volt_sag, _evlist, _show, _store, _mask)
+
+/*
+ * Indicates the end of energy accumulation over an integer number
+ * of half line cycles
+ */
+#define IIO_EVENT_ATTR_CYCEND(_evlist, _show, _store, _mask) \
+       IIO_EVENT_ATTR_SH(cycend, _evlist, _show, _store, _mask)
+
+/* on the rising and falling edge of the the voltage waveform */
+#define IIO_EVENT_ATTR_ZERO_CROSS(_evlist, _show, _store, _mask) \
+       IIO_EVENT_ATTR_SH(zero_cross, _evlist, _show, _store, _mask)
+
+/* the active energy register has overflowed */
+#define IIO_EVENT_ATTR_AENERGY_OVERFLOW(_evlist, _show, _store, _mask) \
+       IIO_EVENT_ATTR_SH(aenergy_overflow, _evlist, _show, _store, _mask)
+
+/* the apparent energy register has overflowed */
+#define IIO_EVENT_ATTR_VAENERGY_OVERFLOW(_evlist, _show, _store, _mask) \
+       IIO_EVENT_ATTR_SH(vaenergy_overflow, _evlist, _show, _store, _mask)
+
+/* the active energy register, VAENERGY, is more than half full */
+#define IIO_EVENT_ATTR_VAENERGY_HALF_FULL(_evlist, _show, _store, _mask) \
+       IIO_EVENT_ATTR_SH(vaenergy_half_full, _evlist, _show, _store, _mask)
+
+/* the power has gone from negative to positive */
+#define IIO_EVENT_ATTR_PPOS(_evlist, _show, _store, _mask) \
+       IIO_EVENT_ATTR_SH(ppos, _evlist, _show, _store, _mask)
+
+/* the power has gone from positive to negative */
+#define IIO_EVENT_ATTR_PNEG(_evlist, _show, _store, _mask) \
+       IIO_EVENT_ATTR_SH(pneg, _evlist, _show, _store, _mask)
+
+/* waveform sample from Channel 1 has exceeded the IPKLVL value */
+#define IIO_EVENT_ATTR_IPKLVL_EXC(_evlist, _show, _store, _mask) \
+       IIO_EVENT_ATTR_SH(ipklvl_exc, _evlist, _show, _store, _mask)
+
+/* waveform sample from Channel 2 has exceeded the VPKLVL value */
+#define IIO_EVENT_ATTR_VPKLVL_EXC(_evlist, _show, _store, _mask) \
+       IIO_EVENT_ATTR_SH(vpklvl_exc, _evlist, _show, _store, _mask)
+
diff --git a/drivers/staging/iio/resolver/Kconfig b/drivers/staging/iio/resolver/Kconfig
new file mode 100644 (file)
index 0000000..a4a3634
--- /dev/null
@@ -0,0 +1,54 @@
+#
+# Resolver/Synchro drivers
+#
+comment "Resolver to digital converters"
+
+config AD2S90
+       tristate "Analog Devices ad2s90 driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices spi resolver
+         to digital converters, ad2s90, provides direct access via sysfs.
+
+config AD2S120X
+       tristate "Analog Devices ad2s120x driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices spi resolver
+         to digital converters, ad2s1200 and ad2s1205, provides direct access
+         via sysfs.
+
+config AD2S1210
+       tristate "Analog Devices ad2s1210 driver"
+       depends on SPI
+       help
+         Say yes here to build support for Analog Devices spi resolver
+         to digital converters, ad2s1210, provides direct access via sysfs.
+
+choice
+       prompt "Resolution Control"
+       depends on AD2S1210
+       default AD2S1210_GPIO_NONE
+       help
+         In normal mode, the resolution of the digital output is selected
+         using the RES0 and RES1 input pins. In configuration mode, the
+         resolution is selected by setting the RES0 and RES1 bits in the
+         control regsiter. When switching between normal mode and configuration
+         mode, there are some schemes to keep them matchs.
+
+config AD2S1210_GPIO_INPUT
+       bool "read resolution from gpio pins"
+       help
+         GPIO pins are sampling RES0 and RES1 pins, read the resolution
+         settings from the GPIO pins.
+
+config AD2S1210_GPIO_OUTPUT
+       bool "set gpio pins to set resolution"
+       help
+         RES0 and RES1 pins are controlled by GPIOs, setting GPIO pins to
+         set the resolution.
+
+config AD2S1210_GPIO_NONE
+       bool "take the responsibility by user"
+
+endchoice
diff --git a/drivers/staging/iio/resolver/Makefile b/drivers/staging/iio/resolver/Makefile
new file mode 100644 (file)
index 0000000..0b84a89
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for Resolver/Synchro drivers
+#
+
+obj-$(CONFIG_AD2S90) += ad2s90.o
+obj-$(CONFIG_AD2S120X) += ad2s120x.o
+obj-$(CONFIG_AD2S1210) += ad2s1210.o
diff --git a/drivers/staging/iio/resolver/ad2s120x.c b/drivers/staging/iio/resolver/ad2s120x.c
new file mode 100644 (file)
index 0000000..8f497a2
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * ad2s120x.c simple support for the ADI Resolver to Digital Converters: AD2S1200/1205
+ *
+ * Copyright (c) 2010-2010 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad2s120x"
+
+/* input pin sample and rdvel is controlled by driver */
+#define AD2S120X_PN    2
+
+/* input clock on serial interface */
+#define AD2S120X_HZ    8192000
+/* clock period in nano second */
+#define AD2S120X_TSCLK (1000000000/AD2S120X_HZ)
+
+struct ad2s120x_state {
+       struct mutex lock;
+       struct iio_dev *idev;
+       struct spi_device *sdev;
+       unsigned short sample;
+       unsigned short rdvel;
+       u8 rx[2];
+       u8 tx[2];
+};
+
+static ssize_t ad2s120x_show_pos_vel(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct spi_message msg;
+       struct spi_transfer xfer;
+       int ret = 0;
+       ssize_t len = 0;
+       u16 pos;
+       s16 vel;
+       u8 status;
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s120x_state *st = idev->dev_data;
+
+       xfer.len = 1;
+       xfer.tx_buf = st->tx;
+       xfer.rx_buf = st->rx;
+       mutex_lock(&st->lock);
+
+       gpio_set_value(st->sample, 0);
+       /* delay (6 * AD2S120X_TSCLK + 20) nano seconds */
+       udelay(1);
+       gpio_set_value(st->sample, 1);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+       status = st->rx[1];
+       pos = (((u16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
+       len = sprintf(buf, "%d %c%c%c%c ", pos,
+                               (status & 0x8) ? 'P' : 'V',
+                               (status & 0x4) ? 'd' : '_',
+                               (status & 0x2) ? 'l' : '_',
+                               (status & 0x1) ? '1' : '0');
+
+       /* delay 18 ns */
+       /* ndelay(18); */
+
+       gpio_set_value(st->rdvel, 0);
+       /* ndelay(5);*/
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+       status = st->rx[1];
+       vel = (st->rx[0] & 0x80) ? 0xf000 : 0;
+       vel |= (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
+       len += sprintf(buf + len, "%d %c%c%c%c\n", vel,
+                               (status & 0x8) ? 'P' : 'V',
+                               (status & 0x4) ? 'd' : '_',
+                               (status & 0x2) ? 'l' : '_',
+                               (status & 0x1) ? '1' : '0');
+error_ret:
+       gpio_set_value(st->rdvel, 1);
+       /* delay (2 * AD2S120X_TSCLK + 20) ns for sample pulse */
+       udelay(1);
+       mutex_unlock(&st->lock);
+
+       return ret ? ret : len;
+}
+
+static ssize_t ad2s120x_show_pos(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct spi_message msg;
+       struct spi_transfer xfer;
+       int ret = 0;
+       ssize_t len = 0;
+       u16 pos;
+       u8 status;
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s120x_state *st = idev->dev_data;
+
+       xfer.len = 1;
+       xfer.tx_buf = st->tx;
+       xfer.rx_buf = st->rx;
+       mutex_lock(&st->lock);
+
+       gpio_set_value(st->sample, 0);
+       /* delay (6 * AD2S120X_TSCLK + 20) nano seconds */
+       udelay(1);
+       gpio_set_value(st->sample, 1);
+       gpio_set_value(st->rdvel, 1);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+       status = st->rx[1];
+       pos = (((u16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
+       len = sprintf(buf, "%d %c%c%c%c ", pos,
+                               (status & 0x8) ? 'P' : 'V',
+                               (status & 0x4) ? 'd' : '_',
+                               (status & 0x2) ? 'l' : '_',
+                               (status & 0x1) ? '1' : '0');
+error_ret:
+       /* delay (2 * AD2S120X_TSCLK + 20) ns for sample pulse */
+       udelay(1);
+       mutex_unlock(&st->lock);
+
+       return ret ? ret : len;
+}
+
+static ssize_t ad2s120x_show_vel(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct spi_message msg;
+       struct spi_transfer xfer;
+       int ret = 0;
+       ssize_t len = 0;
+       s16 vel;
+       u8 status;
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s120x_state *st = idev->dev_data;
+
+       xfer.len = 1;
+       xfer.tx_buf = st->tx;
+       xfer.rx_buf = st->rx;
+       mutex_lock(&st->lock);
+
+       gpio_set_value(st->sample, 0);
+       /* delay (6 * AD2S120X_TSCLK + 20) nano seconds */
+       udelay(1);
+       gpio_set_value(st->sample, 1);
+
+       gpio_set_value(st->rdvel, 0);
+       /* ndelay(5);*/
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+       status = st->rx[1];
+       vel = (st->rx[0] & 0x80) ? 0xf000 : 0;
+       vel |= (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
+       len += sprintf(buf + len, "%d %c%c%c%c\n", vel,
+                               (status & 0x8) ? 'P' : 'V',
+                               (status & 0x4) ? 'd' : '_',
+                               (status & 0x2) ? 'l' : '_',
+                               (status & 0x1) ? '1' : '0');
+error_ret:
+       gpio_set_value(st->rdvel, 1);
+       /* delay (2 * AD2S120X_TSCLK + 20) ns for sample pulse */
+       udelay(1);
+       mutex_unlock(&st->lock);
+
+       return ret ? ret : len;
+}
+
+static IIO_CONST_ATTR(description,
+       "12-Bit R/D Converter with Reference Oscillator");
+static IIO_DEVICE_ATTR(pos_vel, S_IRUGO, ad2s120x_show_pos_vel, NULL, 0);
+static IIO_DEVICE_ATTR(pos, S_IRUGO, ad2s120x_show_pos, NULL, 0);
+static IIO_DEVICE_ATTR(vel, S_IRUGO, ad2s120x_show_vel, NULL, 0);
+
+static struct attribute *ad2s120x_attributes[] = {
+       &iio_const_attr_description.dev_attr.attr,
+       &iio_dev_attr_pos_vel.dev_attr.attr,
+       &iio_dev_attr_pos.dev_attr.attr,
+       &iio_dev_attr_vel.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ad2s120x_attribute_group = {
+       .name = DRV_NAME,
+       .attrs = ad2s120x_attributes,
+};
+
+static int __devinit ad2s120x_probe(struct spi_device *spi)
+{
+       struct ad2s120x_state *st;
+       int pn, ret = 0;
+       unsigned short *pins = spi->dev.platform_data;
+
+       for (pn = 0; pn < AD2S120X_PN; pn++) {
+               if (gpio_request(pins[pn], DRV_NAME)) {
+                       pr_err("%s: request gpio pin %d failed\n",
+                                               DRV_NAME, pins[pn]);
+                       goto error_ret;
+               }
+               gpio_direction_output(pins[pn], 1);
+       }
+
+       st = kzalloc(sizeof(*st), GFP_KERNEL);
+       if (st == NULL) {
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+       spi_set_drvdata(spi, st);
+
+       mutex_init(&st->lock);
+       st->sdev = spi;
+       st->sample = pins[0];
+       st->rdvel = pins[1];
+
+       st->idev = iio_allocate_device();
+       if (st->idev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->idev->dev.parent = &spi->dev;
+       st->idev->num_interrupt_lines = 0;
+       st->idev->event_attrs = NULL;
+
+       st->idev->attrs = &ad2s120x_attribute_group;
+       st->idev->dev_data = (void *)(st);
+       st->idev->driver_module = THIS_MODULE;
+       st->idev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(st->idev);
+       if (ret)
+               goto error_free_dev;
+
+       spi->max_speed_hz = AD2S120X_HZ;
+       spi->mode = SPI_MODE_3;
+       spi_setup(spi);
+
+       return 0;
+
+error_free_dev:
+       iio_free_device(st->idev);
+error_free_st:
+       kfree(st);
+error_ret:
+       for (--pn; pn >= 0; pn--)
+               gpio_free(pins[pn]);
+       return ret;
+}
+
+static int __devexit ad2s120x_remove(struct spi_device *spi)
+{
+       struct ad2s120x_state *st = spi_get_drvdata(spi);
+
+       iio_device_unregister(st->idev);
+       kfree(st);
+
+       return 0;
+}
+
+static struct spi_driver ad2s120x_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = ad2s120x_probe,
+       .remove = __devexit_p(ad2s120x_remove),
+};
+
+static __init int ad2s120x_spi_init(void)
+{
+       return spi_register_driver(&ad2s120x_driver);
+}
+module_init(ad2s120x_spi_init);
+
+static __exit void ad2s120x_spi_exit(void)
+{
+       spi_unregister_driver(&ad2s120x_driver);
+}
+module_exit(ad2s120x_spi_exit);
+
+MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices AD2S1200/1205 Resolver to Digital SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c
new file mode 100644 (file)
index 0000000..34fb21a
--- /dev/null
@@ -0,0 +1,872 @@
+/*
+ * ad2s1210.c support for the ADI Resolver to Digital Converters: AD2S1210
+ *
+ * Copyright (c) 2010-2010 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad2s1210"
+
+#define DEF_CONTROL            0x7E
+
+#define MSB_IS_HIGH            0x80
+#define MSB_IS_LOW             0x7F
+#define PHASE_LOCK_RANGE_44    0x20
+#define ENABLE_HYSTERESIS      0x10
+#define SET_ENRES1             0x08
+#define SET_ENRES0             0x04
+#define SET_RES1               0x02
+#define SET_RES0               0x01
+
+#define SET_ENRESOLUTION       (SET_ENRES1 | SET_ENRES0)
+#define SET_RESOLUTION         (SET_RES1 | SET_RES0)
+
+#define REG_POSITION           0x80
+#define REG_VELOCITY           0x82
+#define REG_LOS_THRD           0x88
+#define REG_DOS_OVR_THRD       0x89
+#define REG_DOS_MIS_THRD       0x8A
+#define REG_DOS_RST_MAX_THRD   0x8B
+#define REG_DOS_RST_MIN_THRD   0x8C
+#define REG_LOT_HIGH_THRD      0x8D
+#define REG_LOT_LOW_THRD       0x8E
+#define REG_EXCIT_FREQ         0x91
+#define REG_CONTROL            0x92
+#define REG_SOFT_RESET         0xF0
+#define REG_FAULT              0xFF
+
+/* pin SAMPLE, A0, A1, RES0, RES1, is controlled by driver */
+#define AD2S1210_SAA           3
+#if defined(CONFIG_AD2S1210_GPIO_INPUT) || defined(CONFIG_AD2S1210_GPIO_OUTPUT)
+# define AD2S1210_RES          2
+#else
+# define AD2S1210_RES          0
+#endif
+#define AD2S1210_PN            (AD2S1210_SAA + AD2S1210_RES)
+
+#define AD2S1210_MIN_CLKIN     6144000
+#define AD2S1210_MAX_CLKIN     10240000
+#define AD2S1210_MIN_EXCIT     2000
+#define AD2S1210_MAX_EXCIT     20000
+#define AD2S1210_MIN_FCW       0x4
+#define AD2S1210_MAX_FCW       0x50
+
+/* default input clock on serial interface */
+#define AD2S1210_DEF_CLKIN     8192000
+/* clock period in nano second */
+#define AD2S1210_DEF_TCK       (1000000000/AD2S1210_DEF_CLKIN)
+#define AD2S1210_DEF_EXCIT     10000
+
+enum ad2s1210_mode {
+       MOD_POS = 0,
+       MOD_VEL,
+       MOD_RESERVED,
+       MOD_CONFIG,
+};
+
+enum ad2s1210_res {
+       RES_10 = 10,
+       RES_12 = 12,
+       RES_14 = 14,
+       RES_16 = 16,
+};
+
+static unsigned int resolution_value[] = {
+               RES_10, RES_12, RES_14, RES_16};
+
+struct ad2s1210_state {
+       struct mutex lock;
+       struct iio_dev *idev;
+       struct spi_device *sdev;
+       struct spi_transfer xfer;
+       unsigned int hysteresis;
+       unsigned int old_data;
+       enum ad2s1210_mode mode;
+       enum ad2s1210_res resolution;
+       unsigned int fclkin;
+       unsigned int fexcit;
+       unsigned short sample;
+       unsigned short a0;
+       unsigned short a1;
+       unsigned short res0;
+       unsigned short res1;
+       u8 rx[3];
+       u8 tx[3];
+};
+
+static inline void start_sample(struct ad2s1210_state *st)
+{
+       gpio_set_value(st->sample, 0);
+}
+
+static inline void stop_sample(struct ad2s1210_state *st)
+{
+       gpio_set_value(st->sample, 1);
+}
+
+static inline void set_mode(enum ad2s1210_mode mode, struct ad2s1210_state *st)
+{
+       switch (mode) {
+       case MOD_POS:
+               gpio_set_value(st->a0, 0);
+               gpio_set_value(st->a1, 0);
+               break;
+       case MOD_VEL:
+               gpio_set_value(st->a0, 0);
+               gpio_set_value(st->a1, 1);
+               break;
+       case MOD_CONFIG:
+               gpio_set_value(st->a0, 1);
+               gpio_set_value(st->a1, 1);
+               break;
+       default:
+               /* set to reserved mode */
+               gpio_set_value(st->a0, 1);
+               gpio_set_value(st->a1, 0);
+       }
+       st->mode = mode;
+}
+
+/* write 1 bytes (address or data) to the chip */
+static int config_write(struct ad2s1210_state *st,
+                                       unsigned char data)
+{
+       struct spi_message msg;
+       int ret = 0;
+
+       st->xfer.len = 1;
+       set_mode(MOD_CONFIG, st);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&st->xfer, &msg);
+       st->tx[0] = data;
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               return ret;
+       st->old_data = 1;
+       return ret;
+}
+
+/* read value from one of the registers */
+static int config_read(struct ad2s1210_state *st,
+                               unsigned char address,
+                                       unsigned char *data)
+{
+       struct spi_message msg;
+       int ret = 0;
+
+       st->xfer.len = 2;
+       set_mode(MOD_CONFIG, st);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&st->xfer, &msg);
+       st->tx[0] = address | MSB_IS_HIGH;
+       st->tx[1] = REG_FAULT;
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               return ret;
+       *data = st->rx[1];
+       st->old_data = 1;
+       return ret;
+}
+
+static inline void update_frequency_control_word(struct ad2s1210_state *st)
+{
+       unsigned char fcw;
+       fcw = (unsigned char)(st->fexcit * (1 << 15) / st->fclkin);
+       if (fcw >= AD2S1210_MIN_FCW && fcw <= AD2S1210_MAX_FCW) {
+               config_write(st, REG_EXCIT_FREQ);
+               config_write(st, fcw);
+       } else
+               pr_err("ad2s1210: FCW out of range\n");
+}
+
+#if defined(CONFIG_AD2S1210_GPIO_INPUT)
+static inline unsigned char read_resolution_pin(struct ad2s1210_state *st)
+{
+       unsigned int data;
+       data = (gpio_get_value(st->res0) << 1)  |
+                       gpio_get_value(st->res1);
+       return resolution_value[data];
+}
+#elif defined(CONFIG_AD2S1210_GPIO_OUTPUT)
+static inline void set_resolution_pin(struct ad2s1210_state *st)
+{
+       switch (st->resolution) {
+       case RES_10:
+               gpio_set_value(st->res0, 0);
+               gpio_set_value(st->res1, 0);
+               break;
+       case RES_12:
+               gpio_set_value(st->res0, 0);
+               gpio_set_value(st->res1, 1);
+               break;
+       case RES_14:
+               gpio_set_value(st->res0, 1);
+               gpio_set_value(st->res1, 0);
+               break;
+       case RES_16:
+               gpio_set_value(st->res0, 1);
+               gpio_set_value(st->res1, 1);
+               break;
+       }
+}
+#endif
+
+static inline void soft_reset(struct ad2s1210_state *st)
+{
+       config_write(st, REG_SOFT_RESET);
+       config_write(st, 0x0);
+}
+
+
+/* return the OLD DATA since last spi bus write */
+static ssize_t ad2s1210_show_raw(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s1210_state *st = idev->dev_data;
+       int ret;
+
+       mutex_lock(&st->lock);
+       if (st->old_data) {
+               ret = sprintf(buf, "0x%x\n", st->rx[0]);
+               st->old_data = 0;
+       } else
+               ret = 0;
+       mutex_unlock(&st->lock);
+       return ret;
+}
+
+static ssize_t ad2s1210_store_raw(struct device *dev,
+               struct device_attribute *attr,
+               const char *buf, size_t len)
+{
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s1210_state *st = idev->dev_data;
+       unsigned long udata;
+       unsigned char data;
+       int ret;
+
+       ret = strict_strtoul(buf, 16, &udata);
+       if (ret)
+               return -EINVAL;
+       data = udata & 0xff;
+       mutex_lock(&st->lock);
+       config_write(st, data);
+       mutex_unlock(&st->lock);
+       return 1;
+}
+
+static ssize_t ad2s1210_store_softreset(struct device *dev,
+                       struct device_attribute *attr,
+                       const char *buf, size_t len)
+{
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s1210_state *st = idev->dev_data;
+       mutex_lock(&st->lock);
+       soft_reset(st);
+       mutex_unlock(&st->lock);
+       return len;
+}
+
+static ssize_t ad2s1210_show_fclkin(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s1210_state *st = idev->dev_data;
+       return sprintf(buf, "%d\n", st->fclkin);
+}
+
+static ssize_t ad2s1210_store_fclkin(struct device *dev,
+                       struct device_attribute *attr,
+                       const char *buf, size_t len)
+{
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s1210_state *st = idev->dev_data;
+       unsigned long fclkin;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &fclkin);
+       if (!ret && fclkin >= AD2S1210_MIN_CLKIN &&
+                               fclkin <= AD2S1210_MAX_CLKIN) {
+               mutex_lock(&st->lock);
+               st->fclkin = fclkin;
+       } else {
+               pr_err("ad2s1210: fclkin out of range\n");
+               return -EINVAL;
+       }
+       update_frequency_control_word(st);
+       soft_reset(st);
+       mutex_unlock(&st->lock);
+       return len;
+}
+
+static ssize_t ad2s1210_show_fexcit(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s1210_state *st = idev->dev_data;
+       return sprintf(buf, "%d\n", st->fexcit);
+}
+
+static ssize_t ad2s1210_store_fexcit(struct device *dev,
+                       struct device_attribute *attr,
+                       const char *buf, size_t len)
+{
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s1210_state *st = idev->dev_data;
+       unsigned long fexcit;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &fexcit);
+       if (!ret && fexcit >= AD2S1210_MIN_EXCIT &&
+                               fexcit <= AD2S1210_MAX_EXCIT) {
+               mutex_lock(&st->lock);
+               st->fexcit = fexcit;
+       } else {
+               pr_err("ad2s1210: excitation frequency out of range\n");
+               return -EINVAL;
+       }
+       update_frequency_control_word(st);
+       soft_reset(st);
+       mutex_unlock(&st->lock);
+       return len;
+}
+
+static ssize_t ad2s1210_show_control(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s1210_state *st = idev->dev_data;
+       unsigned char data;
+       mutex_lock(&st->lock);
+       config_read(st, REG_CONTROL, &data);
+       mutex_unlock(&st->lock);
+       return sprintf(buf, "0x%x\n", data);
+}
+
+static ssize_t ad2s1210_store_control(struct device *dev,
+                       struct device_attribute *attr,
+                       const char *buf, size_t len)
+{
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s1210_state *st = idev->dev_data;
+       unsigned long udata;
+       unsigned char data;
+       int ret;
+
+       ret = strict_strtoul(buf, 16, &udata);
+       if (ret) {
+               ret = -EINVAL;
+               goto error_ret;
+       }
+       mutex_lock(&st->lock);
+       config_write(st, REG_CONTROL);
+       data = udata & MSB_IS_LOW;
+       config_write(st, data);
+       config_read(st, REG_CONTROL, &data);
+       if (data & MSB_IS_HIGH) {
+               ret = -EIO;
+               pr_err("ad2s1210: write control register fail\n");
+               goto error_ret;
+       }
+       st->resolution = resolution_value[data & SET_RESOLUTION];
+#if defined(CONFIG_AD2S1210_GPIO_INPUT)
+       data = read_resolution_pin(st);
+       if (data != st->resolution)
+               pr_warning("ad2s1210: resolution settings not match\n");
+#elif defined(CONFIG_AD2S1210_GPIO_OUTPUT)
+       set_resolution_pin(st);
+#endif
+       ret = len;
+       if (data & ENABLE_HYSTERESIS)
+               st->hysteresis = 1;
+       else
+               st->hysteresis = 0;
+error_ret:
+       mutex_unlock(&st->lock);
+       return ret;
+}
+
+static ssize_t ad2s1210_show_resolution(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s1210_state *st = idev->dev_data;
+       return sprintf(buf, "%d\n", st->resolution);
+}
+
+static ssize_t ad2s1210_store_resolution(struct device *dev,
+                       struct device_attribute *attr,
+                       const char *buf, size_t len)
+{
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s1210_state *st = idev->dev_data;
+       unsigned char data;
+       unsigned long udata;
+       int ret;
+
+       ret = strict_strtoul(buf, 10, &udata);
+       if (ret || udata < RES_10 || udata > RES_16) {
+               pr_err("ad2s1210: resolution out of range\n");
+               return -EINVAL;
+       }
+       mutex_lock(&st->lock);
+       config_read(st, REG_CONTROL, &data);
+       data &= ~SET_RESOLUTION;
+       data |= (udata - RES_10) >> 1;
+       config_write(st, REG_CONTROL);
+       config_write(st, data & MSB_IS_LOW);
+       config_read(st, REG_CONTROL, &data);
+       if (data & MSB_IS_HIGH) {
+               ret = -EIO;
+               pr_err("ad2s1210: setting resolution fail\n");
+               goto error_ret;
+       }
+       st->resolution = resolution_value[data & SET_RESOLUTION];
+#if defined(CONFIG_AD2S1210_GPIO_INPUT)
+       data = read_resolution_pin(st);
+       if (data != st->resolution)
+               pr_warning("ad2s1210: resolution settings not match\n");
+#elif defined(CONFIG_AD2S1210_GPIO_OUTPUT)
+       set_resolution_pin(st);
+#endif
+       ret = len;
+error_ret:
+       mutex_unlock(&st->lock);
+       return ret;
+}
+/* read the fault register since last sample */
+static ssize_t ad2s1210_show_fault(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       int ret = 0;
+       ssize_t len = 0;
+       unsigned char data;
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s1210_state *st = idev->dev_data;
+
+       mutex_lock(&st->lock);
+       ret = config_read(st, REG_FAULT, &data);
+
+       if (ret)
+               goto error_ret;
+       len = sprintf(buf, "0x%x\n", data);
+error_ret:
+       mutex_unlock(&st->lock);
+       return ret ? ret : len;
+}
+
+static ssize_t ad2s1210_clear_fault(struct device *dev,
+                       struct device_attribute *attr,
+                       const char *buf, size_t len)
+{
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s1210_state *st = idev->dev_data;
+       unsigned char data;
+
+       mutex_lock(&st->lock);
+       start_sample(st);
+       /* delay (2 * tck + 20) nano seconds */
+       udelay(1);
+       stop_sample(st);
+       config_read(st, REG_FAULT, &data);
+       start_sample(st);
+       stop_sample(st);
+       mutex_unlock(&st->lock);
+
+       return 0;
+}
+
+static ssize_t ad2s1210_show_reg(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s1210_state *st = idev->dev_data;
+       unsigned char data;
+       struct iio_dev_attr *iattr = to_iio_dev_attr(attr);
+
+       mutex_lock(&st->lock);
+       config_read(st, iattr->address, &data);
+       mutex_unlock(&st->lock);
+       return sprintf(buf, "%d\n", data);
+}
+
+static ssize_t ad2s1210_store_reg(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t len)
+{
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s1210_state *st = idev->dev_data;
+       unsigned long data;
+       int ret;
+       struct iio_dev_attr *iattr = to_iio_dev_attr(attr);
+
+       ret = strict_strtoul(buf, 10, &data);
+       if (ret)
+               return -EINVAL;
+       mutex_lock(&st->lock);
+       config_write(st, iattr->address);
+       config_write(st, data & MSB_IS_LOW);
+       mutex_unlock(&st->lock);
+       return len;
+}
+
+static ssize_t ad2s1210_show_pos(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct spi_message msg;
+       int ret = 0;
+       ssize_t len = 0;
+       u16 pos;
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s1210_state *st = idev->dev_data;
+
+       st->xfer.len = 2;
+       mutex_lock(&st->lock);
+       start_sample(st);
+       /* delay (6 * tck + 20) nano seconds */
+       udelay(1);
+
+       set_mode(MOD_POS, st);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&st->xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+       pos = ((((u16)(st->rx[0])) << 8) | (st->rx[1]));
+       if (st->hysteresis)
+               pos >>= 16 - st->resolution;
+       len = sprintf(buf, "%d\n", pos);
+error_ret:
+       stop_sample(st);
+       /* delay (2 * tck + 20) nano seconds */
+       udelay(1);
+       mutex_unlock(&st->lock);
+
+       return ret ? ret : len;
+}
+
+static ssize_t ad2s1210_show_vel(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct spi_message msg;
+       unsigned short negative;
+       int ret = 0;
+       ssize_t len = 0;
+       s16 vel;
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s1210_state *st = idev->dev_data;
+
+       st->xfer.len = 2;
+       mutex_lock(&st->lock);
+       start_sample(st);
+       /* delay (6 * tck + 20) nano seconds */
+       udelay(1);
+
+       set_mode(MOD_VEL, st);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&st->xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+       negative = st->rx[0] & 0x80;
+       vel = ((((s16)(st->rx[0])) << 8) | (st->rx[1]));
+       vel >>= 16 - st->resolution;
+       if (negative) {
+               negative = (0xffff >> st->resolution) << st->resolution;
+               vel |= negative;
+       }
+       len = sprintf(buf, "%d\n", vel);
+error_ret:
+       stop_sample(st);
+       /* delay (2 * tck + 20) nano seconds */
+       udelay(1);
+       mutex_unlock(&st->lock);
+
+       return ret ? ret : len;
+}
+
+static ssize_t ad2s1210_show_pos_vel(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct spi_message msg;
+       unsigned short negative;
+       int ret = 0;
+       ssize_t len = 0;
+       u16 pos;
+       s16 vel;
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s1210_state *st = idev->dev_data;
+
+       st->xfer.len = 2;
+       mutex_lock(&st->lock);
+       start_sample(st);
+       /* delay (6 * tck + 20) nano seconds */
+       udelay(1);
+
+       set_mode(MOD_POS, st);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&st->xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+       pos = ((((u16)(st->rx[0])) << 8) | (st->rx[1]));
+       if (st->hysteresis)
+               pos >>= 16 - st->resolution;
+       len = sprintf(buf, "%d ", pos);
+
+       st->xfer.len = 2;
+       set_mode(MOD_VEL, st);
+       spi_message_init(&msg);
+       spi_message_add_tail(&st->xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+       negative = st->rx[0] & 0x80;
+       vel = ((((s16)(st->rx[0])) << 8) | (st->rx[1]));
+       vel >>= 16 - st->resolution;
+       if (negative) {
+               negative = (0xffff >> st->resolution) << st->resolution;
+               vel |= negative;
+       }
+       len += sprintf(buf + len, "%d\n", vel);
+error_ret:
+       stop_sample(st);
+       /* delay (2 * tck + 20) nano seconds */
+       udelay(1);
+       mutex_unlock(&st->lock);
+
+       return ret ? ret : len;
+}
+
+static IIO_CONST_ATTR(description,
+       "Variable Resolution, 10-Bit to 16Bit R/D\n\
+Converter with Reference Oscillator");
+static IIO_DEVICE_ATTR(raw_io, S_IRUGO | S_IWUGO,
+               ad2s1210_show_raw, ad2s1210_store_raw, 0);
+static IIO_DEVICE_ATTR(reset, S_IWUGO,
+               NULL, ad2s1210_store_softreset, 0);
+static IIO_DEVICE_ATTR(fclkin, S_IRUGO | S_IWUGO,
+               ad2s1210_show_fclkin, ad2s1210_store_fclkin, 0);
+static IIO_DEVICE_ATTR(fexcit, S_IRUGO | S_IWUGO,
+               ad2s1210_show_fexcit,   ad2s1210_store_fexcit, 0);
+static IIO_DEVICE_ATTR(control, S_IRUGO | S_IWUGO,
+               ad2s1210_show_control, ad2s1210_store_control, 0);
+static IIO_DEVICE_ATTR(bits, S_IRUGO | S_IWUGO,
+               ad2s1210_show_resolution, ad2s1210_store_resolution, 0);
+static IIO_DEVICE_ATTR(fault, S_IRUGO | S_IWUGO,
+               ad2s1210_show_fault, ad2s1210_clear_fault, 0);
+static IIO_DEVICE_ATTR(pos, S_IRUGO,
+               ad2s1210_show_pos, NULL, 0);
+static IIO_DEVICE_ATTR(vel, S_IRUGO,
+               ad2s1210_show_vel, NULL, 0);
+static IIO_DEVICE_ATTR(pos_vel, S_IRUGO,
+               ad2s1210_show_pos_vel, NULL, 0);
+static IIO_DEVICE_ATTR(los_thrd, S_IRUGO | S_IWUGO,
+               ad2s1210_show_reg, ad2s1210_store_reg, REG_LOS_THRD);
+static IIO_DEVICE_ATTR(dos_ovr_thrd, S_IRUGO | S_IWUGO,
+               ad2s1210_show_reg, ad2s1210_store_reg, REG_DOS_OVR_THRD);
+static IIO_DEVICE_ATTR(dos_mis_thrd, S_IRUGO | S_IWUGO,
+               ad2s1210_show_reg, ad2s1210_store_reg, REG_DOS_MIS_THRD);
+static IIO_DEVICE_ATTR(dos_rst_max_thrd, S_IRUGO | S_IWUGO,
+               ad2s1210_show_reg, ad2s1210_store_reg, REG_DOS_RST_MAX_THRD);
+static IIO_DEVICE_ATTR(dos_rst_min_thrd, S_IRUGO | S_IWUGO,
+               ad2s1210_show_reg, ad2s1210_store_reg, REG_DOS_RST_MIN_THRD);
+static IIO_DEVICE_ATTR(lot_high_thrd, S_IRUGO | S_IWUGO,
+               ad2s1210_show_reg, ad2s1210_store_reg, REG_LOT_HIGH_THRD);
+static IIO_DEVICE_ATTR(lot_low_thrd, S_IRUGO | S_IWUGO,
+               ad2s1210_show_reg, ad2s1210_store_reg, REG_LOT_LOW_THRD);
+
+static struct attribute *ad2s1210_attributes[] = {
+       &iio_const_attr_description.dev_attr.attr,
+       &iio_dev_attr_raw_io.dev_attr.attr,
+       &iio_dev_attr_reset.dev_attr.attr,
+       &iio_dev_attr_fclkin.dev_attr.attr,
+       &iio_dev_attr_fexcit.dev_attr.attr,
+       &iio_dev_attr_control.dev_attr.attr,
+       &iio_dev_attr_bits.dev_attr.attr,
+       &iio_dev_attr_fault.dev_attr.attr,
+       &iio_dev_attr_pos.dev_attr.attr,
+       &iio_dev_attr_vel.dev_attr.attr,
+       &iio_dev_attr_pos_vel.dev_attr.attr,
+       &iio_dev_attr_los_thrd.dev_attr.attr,
+       &iio_dev_attr_dos_ovr_thrd.dev_attr.attr,
+       &iio_dev_attr_dos_mis_thrd.dev_attr.attr,
+       &iio_dev_attr_dos_rst_max_thrd.dev_attr.attr,
+       &iio_dev_attr_dos_rst_min_thrd.dev_attr.attr,
+       &iio_dev_attr_lot_high_thrd.dev_attr.attr,
+       &iio_dev_attr_lot_low_thrd.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ad2s1210_attribute_group = {
+       .name = DRV_NAME,
+       .attrs = ad2s1210_attributes,
+};
+
+static int __devinit ad2s1210_initial(struct ad2s1210_state *st)
+{
+       unsigned char data;
+       int ret;
+
+       mutex_lock(&st->lock);
+#if defined(CONFIG_AD2S1210_GPIO_INPUT)
+       st->resolution = read_resolution_pin(st);
+#elif defined(CONFIG_AD2S1210_GPIO_OUTPUT)
+       set_resolution_pin(st);
+#endif
+
+       config_write(st, REG_CONTROL);
+       data = DEF_CONTROL & ~(SET_RESOLUTION);
+       data |= (st->resolution - RES_10) >> 1;
+       config_write(st, data);
+       ret = config_read(st, REG_CONTROL, &data);
+       if (ret)
+               goto error_ret;
+
+       if (data & MSB_IS_HIGH) {
+               ret = -EIO;
+               goto error_ret;
+       }
+
+       update_frequency_control_word(st);
+       soft_reset(st);
+error_ret:
+       mutex_unlock(&st->lock);
+       return ret;
+}
+
+static int __devinit ad2s1210_probe(struct spi_device *spi)
+{
+       struct ad2s1210_state *st;
+       int pn, ret = 0;
+       unsigned short *pins = spi->dev.platform_data;
+
+       for (pn = 0; pn < AD2S1210_PN; pn++) {
+               if (gpio_request(pins[pn], DRV_NAME)) {
+                       pr_err("%s: request gpio pin %d failed\n",
+                                               DRV_NAME, pins[pn]);
+                       goto error_ret;
+               }
+               if (pn < AD2S1210_SAA)
+                       gpio_direction_output(pins[pn], 1);
+               else {
+#if defined(CONFIG_AD2S1210_GPIO_INPUT)
+                       gpio_direction_input(pins[pn]);
+#elif defined(CONFIG_AD2S1210_GPIO_OUTPUT)
+                       gpio_direction_output(pins[pn], 1);
+#endif
+               }
+       }
+
+       st = kzalloc(sizeof(*st), GFP_KERNEL);
+       if (st == NULL) {
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+       spi_set_drvdata(spi, st);
+
+       mutex_init(&st->lock);
+       st->sdev = spi;
+       st->xfer.tx_buf = st->tx;
+       st->xfer.rx_buf = st->rx;
+       st->hysteresis = 1;
+       st->mode = MOD_CONFIG;
+       st->resolution = RES_12;
+       st->fclkin = AD2S1210_DEF_CLKIN;
+       st->fexcit = AD2S1210_DEF_EXCIT;
+       st->sample = pins[0];
+       st->a0 = pins[1];
+       st->a1 = pins[2];
+       st->res0 = pins[3];
+       st->res1 = pins[4];
+
+       st->idev = iio_allocate_device();
+       if (st->idev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->idev->dev.parent = &spi->dev;
+       st->idev->num_interrupt_lines = 0;
+       st->idev->event_attrs = NULL;
+
+       st->idev->attrs = &ad2s1210_attribute_group;
+       st->idev->dev_data = (void *)(st);
+       st->idev->driver_module = THIS_MODULE;
+       st->idev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(st->idev);
+       if (ret)
+               goto error_free_dev;
+
+       if (spi->max_speed_hz != AD2S1210_DEF_CLKIN)
+               st->fclkin = spi->max_speed_hz;
+       spi->mode = SPI_MODE_3;
+       spi_setup(spi);
+
+       ad2s1210_initial(st);
+       return 0;
+
+error_free_dev:
+       iio_free_device(st->idev);
+error_free_st:
+       kfree(st);
+error_ret:
+       for (--pn; pn >= 0; pn--)
+               gpio_free(pins[pn]);
+       return ret;
+}
+
+static int __devexit ad2s1210_remove(struct spi_device *spi)
+{
+       struct ad2s1210_state *st = spi_get_drvdata(spi);
+
+       iio_device_unregister(st->idev);
+       kfree(st);
+
+       return 0;
+}
+
+static struct spi_driver ad2s1210_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = ad2s1210_probe,
+       .remove = __devexit_p(ad2s1210_remove),
+};
+
+static __init int ad2s1210_spi_init(void)
+{
+       return spi_register_driver(&ad2s1210_driver);
+}
+module_init(ad2s1210_spi_init);
+
+static __exit void ad2s1210_spi_exit(void)
+{
+       spi_unregister_driver(&ad2s1210_driver);
+}
+module_exit(ad2s1210_spi_exit);
+
+MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices AD2S1210 Resolver to Digital SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/resolver/ad2s90.c b/drivers/staging/iio/resolver/ad2s90.c
new file mode 100644 (file)
index 0000000..4143535
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * ad2s90.c simple support for the ADI Resolver to Digital Converters: AD2S90
+ *
+ * Copyright (c) 2010-2010 Analog Devices Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+
+#include "../iio.h"
+#include "../sysfs.h"
+
+#define DRV_NAME "ad2s90"
+
+struct ad2s90_state {
+       struct mutex lock;
+       struct iio_dev *idev;
+       struct spi_device *sdev;
+       u8 rx[2];
+       u8 tx[2];
+};
+
+static ssize_t ad2s90_show_angular(struct device *dev,
+                       struct device_attribute *attr, char *buf)
+{
+       struct spi_message msg;
+       struct spi_transfer xfer;
+       int ret;
+       ssize_t len = 0;
+       u16 val;
+       struct iio_dev *idev = dev_get_drvdata(dev);
+       struct ad2s90_state *st = idev->dev_data;
+
+       xfer.len = 1;
+       xfer.tx_buf = st->tx;
+       xfer.rx_buf = st->rx;
+       mutex_lock(&st->lock);
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+       ret = spi_sync(st->sdev, &msg);
+       if (ret)
+               goto error_ret;
+       val = (((u16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4);
+       len = sprintf(buf, "%d\n", val);
+error_ret:
+       mutex_unlock(&st->lock);
+
+       return ret ? ret : len;
+}
+
+#define IIO_DEV_ATTR_SIMPLE_RESOLVER(_show) \
+       IIO_DEVICE_ATTR(angular, S_IRUGO, _show, NULL, 0)
+
+static IIO_CONST_ATTR(description,
+       "Low Cost, Complete 12-Bit Resolver-to-Digital Converter");
+static IIO_DEV_ATTR_SIMPLE_RESOLVER(ad2s90_show_angular);
+
+static struct attribute *ad2s90_attributes[] = {
+       &iio_const_attr_description.dev_attr.attr,
+       &iio_dev_attr_angular.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group ad2s90_attribute_group = {
+       .name = DRV_NAME,
+       .attrs = ad2s90_attributes,
+};
+
+static int __devinit ad2s90_probe(struct spi_device *spi)
+{
+       struct ad2s90_state *st;
+       int ret = 0;
+
+       st = kzalloc(sizeof(*st), GFP_KERNEL);
+       if (st == NULL) {
+               ret = -ENOMEM;
+               goto error_ret;
+       }
+       spi_set_drvdata(spi, st);
+
+       mutex_init(&st->lock);
+       st->sdev = spi;
+
+       st->idev = iio_allocate_device();
+       if (st->idev == NULL) {
+               ret = -ENOMEM;
+               goto error_free_st;
+       }
+       st->idev->dev.parent = &spi->dev;
+       st->idev->num_interrupt_lines = 0;
+       st->idev->event_attrs = NULL;
+
+       st->idev->attrs = &ad2s90_attribute_group;
+       st->idev->dev_data = (void *)(st);
+       st->idev->driver_module = THIS_MODULE;
+       st->idev->modes = INDIO_DIRECT_MODE;
+
+       ret = iio_device_register(st->idev);
+       if (ret)
+               goto error_free_dev;
+
+       /* need 600ns between CS and the first falling edge of SCLK */
+       spi->max_speed_hz = 830000;
+       spi->mode = SPI_MODE_3;
+       spi_setup(spi);
+
+       return 0;
+
+error_free_dev:
+       iio_free_device(st->idev);
+error_free_st:
+       kfree(st);
+error_ret:
+       return ret;
+}
+
+static int __devexit ad2s90_remove(struct spi_device *spi)
+{
+       struct ad2s90_state *st = spi_get_drvdata(spi);
+
+       iio_device_unregister(st->idev);
+       kfree(st);
+
+       return 0;
+}
+
+static struct spi_driver ad2s90_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = ad2s90_probe,
+       .remove = __devexit_p(ad2s90_remove),
+};
+
+static __init int ad2s90_spi_init(void)
+{
+       return spi_register_driver(&ad2s90_driver);
+}
+module_init(ad2s90_spi_init);
+
+static __exit void ad2s90_spi_exit(void)
+{
+       spi_unregister_driver(&ad2s90_driver);
+}
+module_exit(ad2s90_spi_exit);
+
+MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>");
+MODULE_DESCRIPTION("Analog Devices AD2S90 Resolver to Digital SPI driver");
+MODULE_LICENSE("GPL v2");
index ee91a95a8b9502925e6802e5fd2f320d80e3c59d..18bdaac2509d8aa10ea049ba6b0f9dffc5e6c7c6 100644 (file)
@@ -107,6 +107,12 @@ struct iio_const_attr {
 #define IIO_DEV_ATTR_NAME(_show)                               \
        IIO_DEVICE_ATTR(name, S_IRUGO, _show, NULL, 0)
 
+/**
+ * IIO_DEV_ATTR_RESET: resets the device
+ **/
+#define IIO_DEV_ATTR_RESET(_store)                     \
+       IIO_DEVICE_ATTR(reset, S_IWUGO, NULL, _store, 0)
+
 /**
  * IIO_CONST_ATTR_NAME - constant identifier
  * @_string: the name
index 24d3928e7071b2b61e1358ef496566e7ecc4067d..0ba6742d9236a2578ead6e95d97544567eca6a00 100644 (file)
@@ -29,6 +29,8 @@
  *  This file contains all init functions
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/pci.h>
 #include <linux/fs.h>
 #include <linux/interrupt.h>
@@ -169,17 +171,17 @@ static int __devinit intel_sst_probe(struct pci_dev *pci,
 {
        int i, ret = 0;
 
-       pr_debug("sst: Probe for DID %x\n", pci->device);
+       pr_debug("Probe for DID %x\n", pci->device);
        mutex_lock(&drv_ctx_lock);
        if (sst_drv_ctx) {
-               pr_err("sst: Only one sst handle is supported\n");
+               pr_err("Only one sst handle is supported\n");
                mutex_unlock(&drv_ctx_lock);
                return -EBUSY;
        }
 
        sst_drv_ctx = kzalloc(sizeof(*sst_drv_ctx), GFP_KERNEL);
        if (!sst_drv_ctx) {
-               pr_err("sst: intel_sst malloc fail\n");
+               pr_err("malloc fail\n");
                mutex_unlock(&drv_ctx_lock);
                return -ENOMEM;
        }
@@ -226,7 +228,7 @@ static int __devinit intel_sst_probe(struct pci_dev *pci,
        spin_lock_init(&sst_drv_ctx->list_spin_lock);
 
        sst_drv_ctx->max_streams = pci_id->driver_data;
-       pr_debug("sst: Got drv data max stream %d\n",
+       pr_debug("Got drv data max stream %d\n",
                                sst_drv_ctx->max_streams);
        for (i = 1; i <= sst_drv_ctx->max_streams; i++) {
                struct stream_info *stream = &sst_drv_ctx->streams[i];
@@ -241,18 +243,18 @@ static int __devinit intel_sst_probe(struct pci_dev *pci,
                        sst_drv_ctx->mmap_mem =
                                kzalloc(sst_drv_ctx->mmap_len, GFP_KERNEL);
                        if (sst_drv_ctx->mmap_mem) {
-                               pr_debug("sst: Got memory %p size 0x%x\n",
+                               pr_debug("Got memory %p size 0x%x\n",
                                        sst_drv_ctx->mmap_mem,
                                        sst_drv_ctx->mmap_len);
                                break;
                        }
                        if (sst_drv_ctx->mmap_len < (SST_MMAP_STEP*PAGE_SIZE)) {
-                               pr_err("sst: mem alloc fail...abort!!\n");
+                               pr_err("mem alloc fail...abort!!\n");
                                ret = -ENOMEM;
                                goto free_process_reply_wq;
                        }
                        sst_drv_ctx->mmap_len -= (SST_MMAP_STEP * PAGE_SIZE);
-                       pr_debug("sst:mem alloc failed...trying %d\n",
+                       pr_debug("mem alloc failed...trying %d\n",
                                                sst_drv_ctx->mmap_len);
                }
        }
@@ -260,7 +262,7 @@ static int __devinit intel_sst_probe(struct pci_dev *pci,
        /* Init the device */
        ret = pci_enable_device(pci);
        if (ret) {
-               pr_err("sst: device cant be enabled\n");
+               pr_err("device cant be enabled\n");
                goto do_free_mem;
        }
        sst_drv_ctx->pci = pci_dev_get(pci);
@@ -273,25 +275,25 @@ static int __devinit intel_sst_probe(struct pci_dev *pci,
        sst_drv_ctx->shim = pci_ioremap_bar(pci, 1);
        if (!sst_drv_ctx->shim)
                goto do_release_regions;
-       pr_debug("sst: SST Shim Ptr %p\n", sst_drv_ctx->shim);
+       pr_debug("SST Shim Ptr %p\n", sst_drv_ctx->shim);
 
        /* Shared SRAM */
        sst_drv_ctx->mailbox = pci_ioremap_bar(pci, 2);
        if (!sst_drv_ctx->mailbox)
                goto do_unmap_shim;
-       pr_debug("sst: SRAM Ptr %p\n", sst_drv_ctx->mailbox);
+       pr_debug("SRAM Ptr %p\n", sst_drv_ctx->mailbox);
 
        /* IRAM */
        sst_drv_ctx->iram = pci_ioremap_bar(pci, 3);
        if (!sst_drv_ctx->iram)
                goto do_unmap_sram;
-       pr_debug("sst:IRAM Ptr %p\n", sst_drv_ctx->iram);
+       pr_debug("IRAM Ptr %p\n", sst_drv_ctx->iram);
 
        /* DRAM */
        sst_drv_ctx->dram = pci_ioremap_bar(pci, 4);
        if (!sst_drv_ctx->dram)
                goto do_unmap_iram;
-       pr_debug("sst: DRAM Ptr %p\n", sst_drv_ctx->dram);
+       pr_debug("DRAM Ptr %p\n", sst_drv_ctx->dram);
 
        mutex_lock(&sst_drv_ctx->sst_lock);
        sst_drv_ctx->sst_state = SST_UN_INIT;
@@ -301,24 +303,24 @@ static int __devinit intel_sst_probe(struct pci_dev *pci,
                IRQF_SHARED, SST_DRV_NAME, sst_drv_ctx);
        if (ret)
                goto do_unmap_dram;
-       pr_debug("sst: Registered IRQ 0x%x\n", pci->irq);
+       pr_debug("Registered IRQ 0x%x\n", pci->irq);
 
        if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
                ret = misc_register(&lpe_dev);
                if (ret) {
-                       pr_err("sst: couldn't register LPE device\n");
+                       pr_err("couldn't register LPE device\n");
                        goto do_free_irq;
                }
 
                /*Register LPE Control as misc driver*/
                ret = misc_register(&lpe_ctrl);
                if (ret) {
-                       pr_err("sst: couldn't register misc driver\n");
+                       pr_err("couldn't register misc driver\n");
                        goto do_free_irq;
                }
        }
        sst_drv_ctx->lpe_stalled = 0;
-       pr_debug("sst: ...successfully done!!!\n");
+       pr_debug("...successfully done!!!\n");
        return ret;
 
 do_free_irq:
@@ -347,7 +349,7 @@ free_mad_wq:
        destroy_workqueue(sst_drv_ctx->mad_wq);
 do_free_drv_ctx:
        kfree(sst_drv_ctx);
-       pr_err("sst: Probe failed with 0x%x\n", ret);
+       pr_err("Probe failed with 0x%x\n", ret);
        return ret;
 }
 
@@ -404,7 +406,7 @@ int intel_sst_suspend(struct pci_dev *pci, pm_message_t state)
 {
        union config_status_reg csr;
 
-       pr_debug("sst: intel_sst_suspend called\n");
+       pr_debug("intel_sst_suspend called\n");
 
        if (sst_drv_ctx->pb_streams != 0 || sst_drv_ctx->cp_streams != 0)
                return -EPERM;
@@ -434,9 +436,9 @@ int intel_sst_resume(struct pci_dev *pci)
 {
        int ret = 0;
 
-       pr_debug("sst: intel_sst_resume called\n");
+       pr_debug("intel_sst_resume called\n");
        if (sst_drv_ctx->sst_state != SST_SUSPENDED) {
-               pr_err("sst: SST is not in suspended state\n");
+               pr_err("SST is not in suspended state\n");
                return -EPERM;
        }
        sst_drv_ctx = pci_get_drvdata(pci);
@@ -444,7 +446,7 @@ int intel_sst_resume(struct pci_dev *pci)
        pci_restore_state(pci);
        ret = pci_enable_device(pci);
        if (ret)
-               pr_err("sst: device cant be enabled\n");
+               pr_err("device cant be enabled\n");
 
        mutex_lock(&sst_drv_ctx->sst_lock);
        sst_drv_ctx->sst_state = SST_UN_INIT;
@@ -482,14 +484,14 @@ static int __init intel_sst_init(void)
 {
        /* Init all variables, data structure etc....*/
        int ret = 0;
-       pr_debug("sst: INFO: ******** SST DRIVER loading.. Ver: %s\n",
+       pr_debug("INFO: ******** SST DRIVER loading.. Ver: %s\n",
                                       SST_DRIVER_VERSION);
 
        mutex_init(&drv_ctx_lock);
        /* Register with PCI */
        ret = pci_register_driver(&driver);
        if (ret)
-               pr_err("sst: PCI register failed\n");
+               pr_err("PCI register failed\n");
        return ret;
 }
 
@@ -504,7 +506,7 @@ static void __exit intel_sst_exit(void)
 {
        pci_unregister_driver(&driver);
 
-       pr_debug("sst: driver unloaded\n");
+       pr_debug("driver unloaded\n");
        return;
 }
 
index 463e5cba8307fd5694b4e48e81d6f37533ba231d..fb718d47f54b31f2eb523a7d3fcf3f0feb14c1c7 100644 (file)
@@ -27,6 +27,8 @@
  *  Upper layer interfaces (MAD driver, MMF) to SST driver
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/pci.h>
 #include <linux/fs.h>
 #include <linux/uio.h>
@@ -59,14 +61,14 @@ static int intel_sst_check_device(void)
 {
        int retval = 0;
        if (sst_drv_ctx->pmic_state != SND_MAD_INIT_DONE) {
-               pr_warn("sst: Sound card not availble\n ");
+               pr_warn("Sound card not available\n");
                return -EIO;
        }
        if (sst_drv_ctx->sst_state == SST_SUSPENDED) {
-               pr_debug("sst: Resuming from Suspended state\n");
+               pr_debug("Resuming from Suspended state\n");
                retval = intel_sst_resume(sst_drv_ctx->pci);
                if (retval) {
-                       pr_debug("sst: Resume Failed= %#x,abort\n", retval);
+                       pr_debug("Resume Failed= %#x,abort\n", retval);
                        return retval;
                }
        }
@@ -116,7 +118,7 @@ int intel_sst_open(struct inode *i_node, struct file *file_ptr)
                data->pvt_id = sst_assign_pvt_id(sst_drv_ctx);
                data->str_id = 0;
                file_ptr->private_data = (void *)data;
-               pr_debug("sst: pvt_id handle = %d!\n", data->pvt_id);
+               pr_debug("pvt_id handle = %d!\n", data->pvt_id);
        } else {
                retval = -EUSERS;
                mutex_unlock(&sst_drv_ctx->stream_lock);
@@ -145,7 +147,7 @@ int intel_sst_open_cntrl(struct inode *i_node, struct file *file_ptr)
        mutex_lock(&sst_drv_ctx->stream_lock);
        if (sst_drv_ctx->am_cnt < MAX_AM_HANDLES) {
                sst_drv_ctx->am_cnt++;
-               pr_debug("sst: AM handle opened...\n");
+               pr_debug("AM handle opened...\n");
                file_ptr->private_data = NULL;
        } else
                retval = -EACCES;
@@ -167,7 +169,7 @@ int intel_sst_release(struct inode *i_node, struct file *file_ptr)
 {
        struct ioctl_pvt_data *data = file_ptr->private_data;
 
-       pr_debug("sst: Release called, closing app handle\n");
+       pr_debug("Release called, closing app handle\n");
        mutex_lock(&sst_drv_ctx->stream_lock);
        sst_drv_ctx->encoded_cnt--;
        sst_drv_ctx->stream_cnt--;
@@ -183,7 +185,7 @@ int intel_sst_release_cntrl(struct inode *i_node, struct file *file_ptr)
        mutex_lock(&sst_drv_ctx->stream_lock);
        sst_drv_ctx->am_cnt--;
        mutex_unlock(&sst_drv_ctx->stream_lock);
-       pr_debug("sst: AM handle closed\n");
+       pr_debug("AM handle closed\n");
        return 0;
 }
 
@@ -209,7 +211,7 @@ int intel_sst_mmap(struct file *file_ptr, struct vm_area_struct *vma)
                return -EINVAL;
 
        length = vma->vm_end - vma->vm_start;
-       pr_debug("sst: called for stream %d length 0x%x\n", str_id, length);
+       pr_debug("called for stream %d length 0x%x\n", str_id, length);
 
        if (length > sst_drv_ctx->mmap_len)
                return -ENOMEM;
@@ -232,7 +234,7 @@ int intel_sst_mmap(struct file *file_ptr, struct vm_area_struct *vma)
        else
                sst_drv_ctx->streams[str_id].mmapped = true;
 
-       pr_debug("sst: mmap ret 0x%x\n", retval);
+       pr_debug("mmap ret 0x%x\n", retval);
        return retval;
 }
 
@@ -245,7 +247,7 @@ static int intel_sst_mmap_play_capture(u32 str_id,
        struct stream_info *stream;
        struct snd_sst_mmap_buff_entry *buf_entry;
 
-       pr_debug("sst:called for str_id %d\n", str_id);
+       pr_debug("called for str_id %d\n", str_id);
        retval = sst_validate_strid(str_id);
        if (retval)
                return -EINVAL;
@@ -262,7 +264,7 @@ static int intel_sst_mmap_play_capture(u32 str_id,
        stream->curr_bytes = 0;
        stream->cumm_bytes = 0;
 
-       pr_debug("sst:new buffers count %d status %d\n",
+       pr_debug("new buffers count %d status %d\n",
                        mmap_buf->entries, stream->status);
        buf_entry = mmap_buf->buff;
        for (i = 0; i < mmap_buf->entries; i++) {
@@ -291,13 +293,13 @@ static int intel_sst_mmap_play_capture(u32 str_id,
                stream->status = STREAM_RUNNING;
                if (stream->ops == STREAM_OPS_PLAYBACK) {
                        if (sst_play_frame(str_id) < 0) {
-                               pr_warn("sst: play frames fail\n");
+                               pr_warn("play frames fail\n");
                                mutex_unlock(&stream->lock);
                                return -EIO;
                        }
                } else if (stream->ops == STREAM_OPS_CAPTURE) {
                        if (sst_capture_frame(str_id) < 0) {
-                               pr_warn("sst: capture frame fail\n");
+                               pr_warn("capture frame fail\n");
                                mutex_unlock(&stream->lock);
                                return -EIO;
                        }
@@ -313,7 +315,7 @@ static int intel_sst_mmap_play_capture(u32 str_id,
 
        if (retval >= 0)
                retval = stream->cumm_bytes;
-       pr_debug("sst:end of play/rec ioctl bytes = %d!!\n", retval);
+       pr_debug("end of play/rec ioctl bytes = %d!!\n", retval);
        return retval;
 }
 
@@ -335,7 +337,7 @@ static int intel_sst_play_capture(struct stream_info *stream, int str_id)
 
        if (stream->status == STREAM_INIT && stream->prev == STREAM_UN_INIT) {
                /* stream is not started yet */
-               pr_debug("sst: Stream isn't in started state %d, prev %d\n",
+               pr_debug("Stream isn't in started state %d, prev %d\n",
                        stream->status, stream->prev);
        } else if ((stream->status == STREAM_RUNNING ||
                        stream->status == STREAM_PAUSED) &&
@@ -344,13 +346,13 @@ static int intel_sst_play_capture(struct stream_info *stream, int str_id)
                if (stream->ops == STREAM_OPS_PLAYBACK ||
                                stream->ops == STREAM_OPS_PLAYBACK_DRM) {
                        if (sst_play_frame(str_id) < 0) {
-                               pr_warn("sst: play frames failed\n");
+                               pr_warn("play frames failed\n");
                                mutex_unlock(&stream->lock);
                                return -EIO;
                        }
                } else if (stream->ops == STREAM_OPS_CAPTURE) {
                        if (sst_capture_frame(str_id) < 0) {
-                               pr_warn("sst: capture frames failed\n ");
+                               pr_warn("capture frames failed\n");
                                mutex_unlock(&stream->lock);
                                return -EIO;
                        }
@@ -365,7 +367,7 @@ static int intel_sst_play_capture(struct stream_info *stream, int str_id)
        retval = sst_wait_interruptible(sst_drv_ctx, &stream->data_blk);
        if (retval) {
                stream->status = STREAM_INIT;
-               pr_debug("sst: wait returned error...\n");
+               pr_debug("wait returned error...\n");
        }
        return retval;
 }
@@ -463,7 +465,7 @@ static int snd_sst_fill_kernel_list(struct stream_info *stream,
                if (((unsigned long)iovec[index].iov_base
                                + iovec[index].iov_len) <
                                ((unsigned long)iovec[index].iov_base)) {
-                       pr_debug("sst: Buffer overflows");
+                       pr_debug("Buffer overflows\n");
                        kfree(stream_bufs);
                        return -EINVAL;
                }
@@ -476,7 +478,7 @@ static int snd_sst_fill_kernel_list(struct stream_info *stream,
                }
 
                copied_size += size;
-               pr_debug("sst: copied_size - %lx\n", copied_size);
+               pr_debug("copied_size - %lx\n", copied_size);
                if ((copied_size >= mmap_len) ||
                                (stream->sg_index == nr_segs)) {
                        add_to_list = 1;
@@ -506,7 +508,7 @@ static int snd_sst_copy_userbuf_capture(struct stream_info *stream,
        int retval = 0;
 
        /* copy sent buffers */
-       pr_debug("sst: capture stream copying to user now...\n");
+       pr_debug("capture stream copying to user now...\n");
        list_for_each_entry_safe(kbufs, _kbufs, &stream->bufs, node) {
                if (kbufs->in_use == true) {
                        /* copy to user */
@@ -526,7 +528,7 @@ static int snd_sst_copy_userbuf_capture(struct stream_info *stream,
                        }
                }
        }
-       pr_debug("sst: end of cap copy\n");
+       pr_debug("end of cap copy\n");
        return retval;
 }
 
@@ -578,7 +580,7 @@ static int intel_sst_read_write(unsigned int str_id, char __user *buf,
                return -EINVAL;
        stream = &sst_drv_ctx->streams[str_id];
        if (stream->mmapped == true) {
-               pr_warn("sst: user write and stream is mapped");
+               pr_warn("user write and stream is mapped\n");
                return -EIO;
        }
        if (!count)
@@ -586,7 +588,7 @@ static int intel_sst_read_write(unsigned int str_id, char __user *buf,
        stream->curr_bytes = 0;
        stream->cumm_bytes = 0;
        /* copy user buf details */
-       pr_debug("sst: new buffers %p, copy size %d, status %d\n" ,
+       pr_debug("new buffers %p, copy size %d, status %d\n" ,
                        buf, (int) count, (int) stream->status);
 
        stream->buf_type = SST_BUF_USER_STATIC;
@@ -606,7 +608,7 @@ static int intel_sst_read_write(unsigned int str_id, char __user *buf,
        stream->cur_ptr = NULL;
        if (retval >= 0)
                retval = stream->cumm_bytes;
-       pr_debug("sst: end of play/rec bytes = %d!!\n", retval);
+       pr_debug("end of play/rec bytes = %d!!\n", retval);
        return retval;
 }
 
@@ -627,7 +629,7 @@ int intel_sst_write(struct file *file_ptr, const char __user *buf,
        int str_id = data->str_id;
        struct stream_info *stream = &sst_drv_ctx->streams[str_id];
 
-       pr_debug("sst: called for %d\n", str_id);
+       pr_debug("called for %d\n", str_id);
        if (stream->status == STREAM_UN_INIT ||
                stream->status == STREAM_DECODE) {
                return -EBADRQC;
@@ -653,12 +655,12 @@ ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov,
        int str_id = data->str_id;
        struct stream_info *stream;
 
-       pr_debug("sst: entry - %ld\n", nr_segs);
+       pr_debug("entry - %ld\n", nr_segs);
 
        if (is_sync_kiocb(kiocb) == false)
                return -EINVAL;
 
-       pr_debug("sst: called for str_id %d\n", str_id);
+       pr_debug("called for str_id %d\n", str_id);
        retval = sst_validate_strid(str_id);
        if (retval)
                return -EINVAL;
@@ -671,7 +673,7 @@ ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov,
        }
        stream->curr_bytes = 0;
        stream->cumm_bytes = 0;
-       pr_debug("sst: new segs %ld, offset %d, status %d\n" ,
+       pr_debug("new segs %ld, offset %d, status %d\n" ,
                        nr_segs, (int) offset, (int) stream->status);
        stream->buf_type = SST_BUF_USER_STATIC;
        do {
@@ -686,7 +688,7 @@ ssize_t intel_sst_aio_write(struct kiocb *kiocb, const struct iovec *iov,
        stream->cur_ptr = NULL;
        if (retval >= 0)
                retval = stream->cumm_bytes;
-       pr_debug("sst: end of play/rec bytes = %d!!\n", retval);
+       pr_debug("end of play/rec bytes = %d!!\n", retval);
        return retval;
 }
 
@@ -707,7 +709,7 @@ int intel_sst_read(struct file *file_ptr, char __user *buf,
        int str_id = data->str_id;
        struct stream_info *stream = &sst_drv_ctx->streams[str_id];
 
-       pr_debug("sst: called for %d\n", str_id);
+       pr_debug("called for %d\n", str_id);
        if (stream->status == STREAM_UN_INIT ||
                        stream->status == STREAM_DECODE)
                return -EBADRQC;
@@ -732,14 +734,14 @@ ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov,
        int str_id = data->str_id;
        struct stream_info *stream;
 
-       pr_debug("sst: entry - %ld\n", nr_segs);
+       pr_debug("entry - %ld\n", nr_segs);
 
        if (is_sync_kiocb(kiocb) == false) {
-               pr_debug("sst: aio_read from user space is not allowed\n");
+               pr_debug("aio_read from user space is not allowed\n");
                return -EINVAL;
        }
 
-       pr_debug("sst: called for str_id %d\n", str_id);
+       pr_debug("called for str_id %d\n", str_id);
        retval = sst_validate_strid(str_id);
        if (retval)
                return -EINVAL;
@@ -752,7 +754,7 @@ ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov,
        stream->curr_bytes = 0;
        stream->cumm_bytes = 0;
 
-       pr_debug("sst: new segs %ld, offset %d, status %d\n" ,
+       pr_debug("new segs %ld, offset %d, status %d\n" ,
                        nr_segs, (int) offset, (int) stream->status);
        stream->buf_type = SST_BUF_USER_STATIC;
        do {
@@ -767,34 +769,34 @@ ssize_t intel_sst_aio_read(struct kiocb *kiocb, const struct iovec *iov,
        stream->cur_ptr = NULL;
        if (retval >= 0)
                retval = stream->cumm_bytes;
-       pr_debug("sst: end of play/rec bytes = %d!!\n", retval);
+       pr_debug("end of play/rec bytes = %d!!\n", retval);
        return retval;
 }
 
 /* sst_print_stream_params - prints the stream parameters (debug fn)*/
 static void sst_print_stream_params(struct snd_sst_get_stream_params *get_prm)
 {
-       pr_debug("sst: codec params:result =%d\n",
+       pr_debug("codec params:result = %d\n",
                                get_prm->codec_params.result);
-       pr_debug("sst: codec params:stream = %d\n",
+       pr_debug("codec params:stream = %d\n",
                                get_prm->codec_params.stream_id);
-       pr_debug("sst: codec params:codec = %d\n",
+       pr_debug("codec params:codec = %d\n",
                                get_prm->codec_params.codec);
-       pr_debug("sst: codec params:ops = %d\n",
+       pr_debug("codec params:ops = %d\n",
                                get_prm->codec_params.ops);
-       pr_debug("sst: codec params:stream_type= %d\n",
+       pr_debug("codec params:stream_type = %d\n",
                                get_prm->codec_params.stream_type);
-       pr_debug("sst: pcmparams:sfreq= %d\n",
+       pr_debug("pcmparams:sfreq = %d\n",
                                get_prm->pcm_params.sfreq);
-       pr_debug("sst: pcmparams:num_chan= %d\n",
+       pr_debug("pcmparams:num_chan = %d\n",
                                get_prm->pcm_params.num_chan);
-       pr_debug("sst: pcmparams:pcm_wd_sz= %d\n",
+       pr_debug("pcmparams:pcm_wd_sz = %d\n",
                                get_prm->pcm_params.pcm_wd_sz);
        return;
 }
 
 /**
- * intel_sst_ioctl - recieves the device ioctl's
+ * intel_sst_ioctl - receives the device ioctl's
  * @file_ptr:pointer to file
  * @cmd:Ioctl cmd
  * @arg:data
@@ -820,7 +822,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
 
        switch (_IOC_NR(cmd)) {
        case _IOC_NR(SNDRV_SST_STREAM_PAUSE):
-               pr_debug("sst: IOCTL_PAUSE recieved for %d!\n", str_id);
+               pr_debug("IOCTL_PAUSE received for %d!\n", str_id);
                if (minor != STREAM_MODULE) {
                        retval = -EBADRQC;
                        break;
@@ -829,7 +831,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                break;
 
        case _IOC_NR(SNDRV_SST_STREAM_RESUME):
-               pr_debug("sst: SNDRV_SST_IOCTL_RESUME recieved!\n");
+               pr_debug("SNDRV_SST_IOCTL_RESUME received!\n");
                if (minor != STREAM_MODULE) {
                        retval = -EBADRQC;
                        break;
@@ -840,7 +842,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
        case _IOC_NR(SNDRV_SST_STREAM_SET_PARAMS): {
                struct snd_sst_params *str_param = (struct snd_sst_params *)arg;
 
-               pr_debug("sst: IOCTL_SET_PARAMS recieved!\n");
+               pr_debug("IOCTL_SET_PARAMS received!\n");
                if (minor != STREAM_MODULE) {
                        retval = -EBADRQC;
                        break;
@@ -864,7 +866,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                                        retval = -EINVAL;
                        }
                } else {
-                       pr_debug("sst: SET_STREAM_PARAMS recieved!\n");
+                       pr_debug("SET_STREAM_PARAMS received!\n");
                        /* allocated set params only */
                        retval = sst_set_stream_param(str_id, str_param);
                        /* Block the call for reply */
@@ -887,21 +889,21 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
        case _IOC_NR(SNDRV_SST_SET_VOL): {
                struct snd_sst_vol *set_vol;
                struct snd_sst_vol *rec_vol = (struct snd_sst_vol *)arg;
-               pr_debug("sst: SET_VOLUME recieved for %d!\n",
+               pr_debug("SET_VOLUME received for %d!\n",
                                rec_vol->stream_id);
                if (minor == STREAM_MODULE && rec_vol->stream_id == 0) {
-                       pr_debug("sst: invalid operation!\n");
+                       pr_debug("invalid operation!\n");
                        retval = -EPERM;
                        break;
                }
                set_vol = kzalloc(sizeof(*set_vol), GFP_ATOMIC);
                if (!set_vol) {
-                       pr_debug("sst: mem allocation failed\n");
+                       pr_debug("mem allocation failed\n");
                        retval = -ENOMEM;
                        break;
                }
                if (copy_from_user(set_vol, rec_vol, sizeof(*set_vol))) {
-                       pr_debug("sst: copy failed\n");
+                       pr_debug("copy failed\n");
                        retval = -EFAULT;
                        break;
                }
@@ -912,10 +914,10 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
        case _IOC_NR(SNDRV_SST_GET_VOL): {
                struct snd_sst_vol *rec_vol = (struct snd_sst_vol *)arg;
                struct snd_sst_vol get_vol;
-               pr_debug("sst: IOCTL_GET_VOLUME recieved for stream = %d!\n",
+               pr_debug("IOCTL_GET_VOLUME received for stream = %d!\n",
                                rec_vol->stream_id);
                if (minor == STREAM_MODULE && rec_vol->stream_id == 0) {
-                       pr_debug("sst: invalid operation!\n");
+                       pr_debug("invalid operation!\n");
                        retval = -EPERM;
                        break;
                }
@@ -925,7 +927,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                        retval = -EIO;
                        break;
                }
-               pr_debug("sst: id:%d\n, vol:%d, ramp_dur:%d, ramp_type:%d\n",
+               pr_debug("id:%d\n, vol:%d, ramp_dur:%d, ramp_type:%d\n",
                                get_vol.stream_id, get_vol.volume,
                                get_vol.ramp_duration, get_vol.ramp_type);
                if (copy_to_user((struct snd_sst_vol *)arg,
@@ -940,7 +942,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
        case _IOC_NR(SNDRV_SST_MUTE): {
                struct snd_sst_mute *set_mute;
                struct snd_sst_vol *rec_mute = (struct snd_sst_vol *)arg;
-               pr_debug("sst: SNDRV_SST_SET_VOLUME recieved for %d!\n",
+               pr_debug("SNDRV_SST_SET_VOLUME received for %d!\n",
                        rec_mute->stream_id);
                if (minor == STREAM_MODULE && rec_mute->stream_id == 0) {
                        retval = -EPERM;
@@ -962,7 +964,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
        case _IOC_NR(SNDRV_SST_STREAM_GET_PARAMS): {
                struct snd_sst_get_stream_params get_params;
 
-               pr_debug("sst: IOCTL_GET_PARAMS recieved!\n");
+               pr_debug("IOCTL_GET_PARAMS received!\n");
                if (minor != 0) {
                        retval = -EBADRQC;
                        break;
@@ -984,7 +986,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
 
        case _IOC_NR(SNDRV_SST_MMAP_PLAY):
        case _IOC_NR(SNDRV_SST_MMAP_CAPTURE):
-               pr_debug("sst: SNDRV_SST_MMAP_PLAY/CAPTURE recieved!\n");
+               pr_debug("SNDRV_SST_MMAP_PLAY/CAPTURE received!\n");
                if (minor != STREAM_MODULE) {
                        retval = -EBADRQC;
                        break;
@@ -994,7 +996,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                break;
 
        case _IOC_NR(SNDRV_SST_STREAM_DROP):
-               pr_debug("sst: SNDRV_SST_IOCTL_DROP recieved!\n");
+               pr_debug("SNDRV_SST_IOCTL_DROP received!\n");
                if (minor != STREAM_MODULE) {
                        retval = -EINVAL;
                        break;
@@ -1007,7 +1009,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                struct snd_sst_tstamp tstamp = {0};
                unsigned long long time, freq, mod;
 
-               pr_debug("sst: SNDRV_SST_STREAM_GET_TSTAMP recieved!\n");
+               pr_debug("SNDRV_SST_STREAM_GET_TSTAMP received!\n");
                if (minor != STREAM_MODULE) {
                        retval = -EBADRQC;
                        break;
@@ -1028,7 +1030,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
        case _IOC_NR(SNDRV_SST_STREAM_START):{
                struct stream_info *stream;
 
-               pr_debug("sst: SNDRV_SST_STREAM_START recieved!\n");
+               pr_debug("SNDRV_SST_STREAM_START received!\n");
                if (minor != STREAM_MODULE) {
                        retval = -EINVAL;
                        break;
@@ -1067,7 +1069,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
        case _IOC_NR(SNDRV_SST_SET_TARGET_DEVICE): {
                struct snd_sst_target_device *target_device;
 
-               pr_debug("sst: SET_TARGET_DEVICE recieved!\n");
+               pr_debug("SET_TARGET_DEVICE received!\n");
                target_device = (struct snd_sst_target_device *)arg;
                BUG_ON(!target_device);
                if (minor != AM_MODULE) {
@@ -1082,7 +1084,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                struct snd_sst_driver_info *info =
                        (struct snd_sst_driver_info *)arg;
 
-               pr_debug("sst: SNDRV_SST_DRIVER_INFO recived\n");
+               pr_debug("SNDRV_SST_DRIVER_INFO received\n");
                info->version = SST_VERSION_NUM;
                /* hard coding, shud get sumhow later */
                info->active_pcm_streams = sst_drv_ctx->stream_cnt -
@@ -1102,7 +1104,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                struct snd_sst_buff_entry ibuf_temp[param->ibufs->entries],
                                obuf_temp[param->obufs->entries];
 
-               pr_debug("sst: SNDRV_SST_STREAM_DECODE recived\n");
+               pr_debug("SNDRV_SST_STREAM_DECODE received\n");
                if (minor != STREAM_MODULE) {
                        retval = -EBADRQC;
                        break;
@@ -1155,7 +1157,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
        }
 
        case _IOC_NR(SNDRV_SST_STREAM_DRAIN):
-               pr_debug("sst: SNDRV_SST_STREAM_DRAIN recived\n");
+               pr_debug("SNDRV_SST_STREAM_DRAIN received\n");
                if (minor != STREAM_MODULE) {
                        retval = -EINVAL;
                        break;
@@ -1167,7 +1169,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
                unsigned long long *bytes = (unsigned long long *)arg;
                struct snd_sst_tstamp tstamp = {0};
 
-               pr_debug("sst: STREAM_BYTES_DECODED recieved!\n");
+               pr_debug("STREAM_BYTES_DECODED received!\n");
                if (minor != STREAM_MODULE) {
                        retval = -EINVAL;
                        break;
@@ -1184,7 +1186,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
        case _IOC_NR(SNDRV_SST_FW_INFO): {
                struct snd_sst_fw_info *fw_info;
 
-               pr_debug("sst: SNDRV_SST_FW_INFO recived\n");
+               pr_debug("SNDRV_SST_FW_INFO received\n");
 
                fw_info = kzalloc(sizeof(*fw_info), GFP_ATOMIC);
                if (!fw_info) {
@@ -1210,7 +1212,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg)
        default:
                retval = -EINVAL;
        }
-       pr_debug("sst: intel_sst_ioctl:complete ret code = %d\n", retval);
+       pr_debug("intel_sst_ioctl:complete ret code = %d\n", retval);
        return retval;
 }
 
index 669e298016f26062f08719959eec53c47305698e..5b10ddf60092152d6e181b9dc1adca55c6562027 100644 (file)
@@ -26,6 +26,8 @@
  *  Upper layer interfaces (MAD driver, MMF) to SST driver
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/fs.h>
@@ -52,10 +54,10 @@ int sst_download_fw(void)
                name = SST_FW_FILENAME_MRST;
        else
                name = SST_FW_FILENAME_MFLD;
-       pr_debug("sst: Downloading %s FW now...\n", name);
+       pr_debug("Downloading %s FW now...\n", name);
        retval = request_firmware(&fw_sst, name, &sst_drv_ctx->pci->dev);
        if (retval) {
-               pr_err("sst: request fw failed %d\n", retval);
+               pr_err("request fw failed %d\n", retval);
                return retval;
        }
        sst_drv_ctx->alloc_block[0].sst_id = FW_DWNL_ID;
@@ -66,7 +68,7 @@ int sst_download_fw(void)
 
        retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[0]);
        if (retval)
-               pr_err("sst: fw download failed %d\n" , retval);
+               pr_err("fw download failed %d\n" , retval);
 end_restore:
        release_firmware(fw_sst);
        sst_drv_ctx->alloc_block[0].sst_id = BLOCK_UNINIT;
@@ -90,7 +92,7 @@ int sst_stalled(void)
 
                retry--;
        }
-       pr_debug("sst: in Stalled State\n");
+       pr_debug("in Stalled State\n");
        return retval;
 }
 
@@ -138,23 +140,23 @@ int sst_get_stream_allocated(struct snd_sst_params *str_param,
        retval = sst_alloc_stream((char *) &str_param->sparams, str_param->ops,
                                str_param->codec, str_param->device_type);
        if (retval < 0) {
-               pr_err("sst: sst_alloc_stream failed %d\n", retval);
+               pr_err("sst_alloc_stream failed %d\n", retval);
                return retval;
        }
-       pr_debug("sst: Stream allocated %d\n", retval);
+       pr_debug("Stream allocated %d\n", retval);
        str_id = retval;
        str_info = &sst_drv_ctx->streams[str_id];
        /* Block the call for reply */
        retval = sst_wait_interruptible_timeout(sst_drv_ctx,
                        &str_info->ctrl_blk, SST_BLOCK_TIMEOUT);
        if ((retval != 0) || (str_info->ctrl_blk.ret_code != 0)) {
-               pr_debug("sst: FW alloc failed retval %d, ret_code %d\n",
+               pr_debug("FW alloc failed retval %d, ret_code %d\n",
                                retval, str_info->ctrl_blk.ret_code);
                str_id = -str_info->ctrl_blk.ret_code; /*return error*/
                *lib_dnld = str_info->ctrl_blk.data;
                sst_clean_stream(str_info);
        } else
-               pr_debug("sst: FW Stream allocated sucess\n");
+               pr_debug("FW Stream allocated success\n");
        return str_id; /*will ret either error (in above if) or correct str id*/
 }
 
@@ -196,14 +198,14 @@ int sst_get_stream(struct snd_sst_params *str_param)
                /* codec download is required */
                struct snd_sst_alloc_response *response;
 
-               pr_debug("sst: Codec is required.... trying that\n");
+               pr_debug("Codec is required.... trying that\n");
                if (lib_dnld == NULL) {
-                       pr_err("sst: lib download null!!! abort\n");
+                       pr_err("lib download null!!! abort\n");
                        return -EIO;
                }
                i = sst_get_block_stream(sst_drv_ctx);
                response = sst_drv_ctx->alloc_block[i].ops_block.data;
-               pr_debug("sst: alloc block allocated = %d\n", i);
+               pr_debug("alloc block allocated = %d\n", i);
                if (i < 0) {
                        kfree(lib_dnld);
                        return -ENOMEM;
@@ -213,15 +215,15 @@ int sst_get_stream(struct snd_sst_params *str_param)
 
                sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
                if (!retval) {
-                       pr_debug("sst: codec was downloaded sucesfully\n");
+                       pr_debug("codec was downloaded successfully\n");
 
                        retval = sst_get_stream_allocated(str_param, &lib_dnld);
                        if (retval <= 0)
                                goto err;
 
-                       pr_debug("sst: Alloc done stream id %d\n", retval);
+                       pr_debug("Alloc done stream id %d\n", retval);
                } else {
-                       pr_debug("sst: codec download failed\n");
+                       pr_debug("codec download failed\n");
                        retval = -EIO;
                        goto err;
                }
@@ -279,10 +281,10 @@ void sst_process_mad_ops(struct work_struct *work)
                retval = sst_start_stream(mad_ops->stream_id);
                break;
        case SST_SND_STREAM_PROCESS:
-               pr_debug("sst: play/capt frames...\n");
+               pr_debug("play/capt frames...\n");
                break;
        default:
-               pr_err("sst:  wrong control_ops reported\n");
+               pr_err(" wrong control_ops reported\n");
        }
        return;
 }
@@ -301,19 +303,19 @@ int sst_control_set(int control_element, void *value)
 
        if (sst_drv_ctx->sst_state == SST_SUSPENDED) {
                /*LPE is suspended, resume it before proceding*/
-               pr_debug("sst: Resuming from Suspended state\n");
+               pr_debug("Resuming from Suspended state\n");
                retval = intel_sst_resume(sst_drv_ctx->pci);
                if (retval) {
-                       pr_err("sst: Resume Failed = %#x, abort\n", retval);
+                       pr_err("Resume Failed = %#x, abort\n", retval);
                        return retval;
                }
        }
        if (sst_drv_ctx->sst_state == SST_UN_INIT) {
                /* FW is not downloaded */
-               pr_debug("sst: DSP Downloading FW now...\n");
+               pr_debug("DSP Downloading FW now...\n");
                retval = sst_download_fw();
                if (retval) {
-                       pr_err("sst: FW download fail %x, abort\n", retval);
+                       pr_err("FW download fail %x, abort\n", retval);
                        return retval;
                }
                if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID &&
@@ -361,7 +363,7 @@ int sst_control_set(int control_element, void *value)
                struct pcm_stream_info *str_info;
                struct stream_info *stream;
 
-               pr_debug("sst: stream init called\n");
+               pr_debug("stream init called\n");
                str_info = (struct pcm_stream_info *)value;
                str_id = str_info->str_id;
                retval = sst_validate_strid(str_id);
@@ -369,7 +371,7 @@ int sst_control_set(int control_element, void *value)
                        break;
 
                stream = &sst_drv_ctx->streams[str_id];
-               pr_debug("sst: setting the period ptrs\n");
+               pr_debug("setting the period ptrs\n");
                stream->pcm_substream = str_info->mad_substream;
                stream->period_elapsed = str_info->period_elapsed;
                stream->sfreq = str_info->sfreq;
@@ -398,14 +400,14 @@ int sst_control_set(int control_element, void *value)
                        +(str_id * sizeof(fw_tstamp))),
                        sizeof(fw_tstamp));
 
-               pr_debug("sst: Pointer Query on strid = %d ops %d\n",
+               pr_debug("Pointer Query on strid = %d ops %d\n",
                                                str_id, stream->ops);
 
                if (stream->ops == STREAM_OPS_PLAYBACK)
                        stream_info->buffer_ptr = fw_tstamp.samples_rendered;
                else
                        stream_info->buffer_ptr = fw_tstamp.samples_processed;
-               pr_debug("sst: Samples rendered = %llu, buffer ptr %llu\n",
+               pr_debug("Samples rendered = %llu, buffer ptr %llu\n",
                        fw_tstamp.samples_rendered, stream_info->buffer_ptr);
                break;
        }
@@ -417,7 +419,7 @@ int sst_control_set(int control_element, void *value)
        }
        default:
                /* Illegal case */
-               pr_warn("sst: illegal req\n");
+               pr_warn("illegal req\n");
                return -EINVAL;
        }
 
@@ -439,12 +441,12 @@ struct intel_sst_card_ops sst_pmic_ops = {
 int register_sst_card(struct intel_sst_card_ops *card)
 {
        if (!sst_drv_ctx) {
-               pr_err("sst: No SST driver register card reject\n");
+               pr_err("No SST driver register card reject\n");
                return -ENODEV;
        }
 
        if (!card || !card->module_name) {
-               pr_err("sst: Null Pointer Passed\n");
+               pr_err("Null Pointer Passed\n");
                return -EINVAL;
        }
        if (sst_drv_ctx->pmic_state == SND_MAD_UN_INIT) {
@@ -460,13 +462,13 @@ int register_sst_card(struct intel_sst_card_ops *card)
                        sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT;
                        return 0;
                } else {
-                       pr_err("sst: strcmp fail %s\n", card->module_name);
+                       pr_err("strcmp fail %s\n", card->module_name);
                        return -EINVAL;
                }
 
        } else {
                /* already registered a driver */
-               pr_err("sst: Repeat for registeration..denied\n");
+               pr_err("Repeat for registration..denied\n");
                return -EBADRQC;
        }
        return 0;
@@ -486,7 +488,7 @@ void unregister_sst_card(struct intel_sst_card_ops *card)
                /* unreg */
                sst_pmic_ops.module_name = "";
                sst_drv_ctx->pmic_state = SND_MAD_UN_INIT;
-               pr_debug("sst: Unregistered %s\n", card->module_name);
+               pr_debug("Unregistered %s\n", card->module_name);
        }
        return;
 }
index d80a6ee2deb8d061acc90ce7ede2a4311cfa5f6c..d1b0537cf4b82f270382c2d00fc8c037efae8de0 100644 (file)
@@ -29,6 +29,9 @@
  *  This file contains all dsp controlling functions like firmware download,
  * setting/resetting dsp cores, etc
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/pci.h>
 #include <linux/fs.h>
 #include <linux/firmware.h>
@@ -47,7 +50,7 @@ static int intel_sst_reset_dsp_mrst(void)
 {
        union config_status_reg csr;
 
-       pr_debug("sst: Resetting the DSP in mrst\n");
+       pr_debug("Resetting the DSP in mrst\n");
        csr.full = 0x3a2;
        sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
        csr.full = sst_shim_read(sst_drv_ctx->shim, SST_CSR);
@@ -68,7 +71,7 @@ static int intel_sst_reset_dsp_medfield(void)
 {
        union config_status_reg csr;
 
-       pr_debug("sst: Resetting the DSP in medfield\n");
+       pr_debug("Resetting the DSP in medfield\n");
        csr.full = 0x048303E2;
        sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
 
@@ -90,7 +93,7 @@ static int sst_start_mrst(void)
        csr.part.run_stall = 0;
        csr.part.sst_reset = 0;
        csr.part.strb_cntr_rst = 1;
-       pr_debug("sst: Setting SST to execute_mrst 0x%x\n", csr.full);
+       pr_debug("Setting SST to execute_mrst 0x%x\n", csr.full);
        sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
 
        return 0;
@@ -111,7 +114,7 @@ static int sst_start_medfield(void)
        sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
        csr.full = 0x04830061;
        sst_shim_write(sst_drv_ctx->shim, SST_CSR, csr.full);
-       pr_debug("sst: Starting the DSP_medfld\n");
+       pr_debug("Starting the DSP_medfld\n");
 
        return 0;
 }
@@ -130,16 +133,16 @@ static int sst_parse_module(struct fw_module_header *module)
        u32 count;
        void __iomem *ram;
 
-       pr_debug("sst: module sign %s size %x blocks %x type %x\n",
+       pr_debug("module sign %s size %x blocks %x type %x\n",
                        module->signature, module->mod_size,
                        module->blocks, module->type);
-       pr_debug("sst: module entrypoint 0x%x\n", module->entry_point);
+       pr_debug("module entrypoint 0x%x\n", module->entry_point);
 
        block = (void *)module + sizeof(*module);
 
        for (count = 0; count < module->blocks; count++) {
                if (block->size <= 0) {
-                       pr_err("sst: block size invalid\n");
+                       pr_err("block size invalid\n");
                        return -EINVAL;
                }
                switch (block->type) {
@@ -150,7 +153,7 @@ static int sst_parse_module(struct fw_module_header *module)
                        ram = sst_drv_ctx->dram;
                        break;
                default:
-                       pr_err("sst: wrong ram type0x%x in block0x%x\n",
+                       pr_err("wrong ram type0x%x in block0x%x\n",
                                        block->type, count);
                        return -EINVAL;
                }
@@ -184,10 +187,10 @@ static int sst_parse_fw_image(const struct firmware *sst_fw)
        if ((strncmp(header->signature, SST_FW_SIGN, 4) != 0) ||
                        (sst_fw->size != header->file_size + sizeof(*header))) {
                /* Invalid FW signature */
-               pr_err("sst: InvalidFW sign/filesize mismatch\n");
+               pr_err("Invalid FW sign/filesize mismatch\n");
                return -EINVAL;
        }
-       pr_debug("sst: header sign=%s size=%x modules=%x fmt=%x size=%x\n",
+       pr_debug("header sign=%s size=%x modules=%x fmt=%x size=%x\n",
                        header->signature, header->file_size, header->modules,
                        header->file_format, sizeof(*header));
        module = (void *)sst_fw->data + sizeof(*header);
@@ -214,7 +217,7 @@ int sst_load_fw(const struct firmware *fw, void *context)
 {
        int ret_val;
 
-       pr_debug("sst: load_fw called\n");
+       pr_debug("load_fw called\n");
        BUG_ON(!fw);
 
        if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID)
@@ -239,7 +242,7 @@ int sst_load_fw(const struct firmware *fw, void *context)
        if (ret_val)
                return ret_val;
 
-       pr_debug("sst: fw loaded successful!!!\n");
+       pr_debug("fw loaded successful!!!\n");
        return ret_val;
 }
 
@@ -261,7 +264,7 @@ static int sst_download_library(const struct firmware *fw_lib,
 
        pvt_id = sst_assign_pvt_id(sst_drv_ctx);
        i = sst_get_block_stream(sst_drv_ctx);
-       pr_debug("sst: alloc block allocated = %d, pvt_id %d\n", i, pvt_id);
+       pr_debug("alloc block allocated = %d, pvt_id %d\n", i, pvt_id);
        if (i < 0) {
                kfree(msg);
                return -ENOMEM;
@@ -281,11 +284,11 @@ static int sst_download_library(const struct firmware *fw_lib,
        if (retval) {
                /* error */
                sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
-               pr_err("sst: Prep codec downloaded failed %d\n",
+               pr_err("Prep codec downloaded failed %d\n",
                                retval);
                return -EIO;
        }
-       pr_debug("sst: FW responded, ready for download now...\n");
+       pr_debug("FW responded, ready for download now...\n");
        /* downloading on success */
        mutex_lock(&sst_drv_ctx->sst_lock);
        sst_drv_ctx->sst_state = SST_FW_LOADED;
@@ -325,7 +328,7 @@ static int sst_download_library(const struct firmware *fw_lib,
        list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
        spin_unlock(&sst_drv_ctx->list_spin_lock);
        sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
-       pr_debug("sst: Waiting for FW response Download complete\n");
+       pr_debug("Waiting for FW response Download complete\n");
        sst_drv_ctx->alloc_block[i].ops_block.condition = false;
        retval = sst_wait_timeout(sst_drv_ctx, &sst_drv_ctx->alloc_block[i]);
        if (retval) {
@@ -337,7 +340,7 @@ static int sst_download_library(const struct firmware *fw_lib,
                return -EIO;
        }
 
-       pr_debug("sst: FW sucess on Download complete\n");
+       pr_debug("FW success on Download complete\n");
        sst_drv_ctx->alloc_block[i].sst_id = BLOCK_UNINIT;
        mutex_lock(&sst_drv_ctx->sst_lock);
        sst_drv_ctx->sst_state = SST_FW_RUNNING;
@@ -360,14 +363,14 @@ static int sst_validate_library(const struct firmware *fw_lib,
 
        header = (struct fw_header *)fw_lib->data;
        if (header->modules != 1) {
-               pr_err("sst: Module no mismatch found\n ");
+               pr_err("Module no mismatch found\n");
                err = -EINVAL;
                goto exit;
        }
        module = (void *)fw_lib->data + sizeof(*header);
        *entry_point = module->entry_point;
-       pr_debug("sst: Module entry point 0x%x\n", *entry_point);
-       pr_debug("sst: Module Sign %s, Size 0x%x, Blocks 0x%x Type 0x%x\n",
+       pr_debug("Module entry point 0x%x\n", *entry_point);
+       pr_debug("Module Sign %s, Size 0x%x, Blocks 0x%x Type 0x%x\n",
                        module->signature, module->mod_size,
                        module->blocks, module->type);
 
@@ -381,20 +384,20 @@ static int sst_validate_library(const struct firmware *fw_lib,
                        dsize += block->size;
                        break;
                default:
-                       pr_err("sst: Invalid block type for 0x%x\n", n_blk);
+                       pr_err("Invalid block type for 0x%x\n", n_blk);
                        err = -EINVAL;
                        goto exit;
                }
                block = (void *)block + sizeof(*block) + block->size;
        }
        if (isize > slot->iram_size || dsize > slot->dram_size) {
-               pr_err("sst: library exceeds size allocated\n");
+               pr_err("library exceeds size allocated\n");
                err = -EINVAL;
                goto exit;
        } else
-               pr_debug("sst: Library is safe for download...\n");
+               pr_debug("Library is safe for download...\n");
 
-       pr_debug("sst: iram 0x%x, dram 0x%x, iram 0x%x, dram 0x%x\n",
+       pr_debug("iram 0x%x, dram 0x%x, iram 0x%x, dram 0x%x\n",
                        isize, dsize, slot->iram_size, slot->dram_size);
 exit:
        return err;
@@ -414,15 +417,15 @@ int sst_load_library(struct snd_sst_lib_download *lib, u8 ops)
 
        memset(buf, 0, sizeof(buf));
 
-       pr_debug("sst: Lib Type 0x%x, Slot 0x%x, ops 0x%x\n",
+       pr_debug("Lib Type 0x%x, Slot 0x%x, ops 0x%x\n",
                        lib->lib_info.lib_type, lib->slot_info.slot_num, ops);
-       pr_debug("sst: Version 0x%x, name %s, caps 0x%x media type 0x%x\n",
+       pr_debug("Version 0x%x, name %s, caps 0x%x media type 0x%x\n",
                lib->lib_info.lib_version, lib->lib_info.lib_name,
                lib->lib_info.lib_caps, lib->lib_info.media_type);
 
-       pr_debug("sst: IRAM Size 0x%x, offset 0x%x\n",
+       pr_debug("IRAM Size 0x%x, offset 0x%x\n",
                lib->slot_info.iram_size, lib->slot_info.iram_offset);
-       pr_debug("sst: DRAM Size 0x%x, offset 0x%x\n",
+       pr_debug("DRAM Size 0x%x, offset 0x%x\n",
                lib->slot_info.dram_size, lib->slot_info.dram_offset);
 
        switch (lib->lib_info.lib_type) {
@@ -442,7 +445,7 @@ int sst_load_library(struct snd_sst_lib_download *lib, u8 ops)
                type = "wma9_";
                break;
        default:
-               pr_err("sst: Invalid codec type\n");
+               pr_err("Invalid codec type\n");
                error = -EINVAL;
                goto wake;
        }
@@ -458,11 +461,11 @@ int sst_load_library(struct snd_sst_lib_download *lib, u8 ops)
                        lib->slot_info.slot_num);
        len += snprintf(buf + len, sizeof(buf) - len, ".bin");
 
-       pr_debug("sst: Requesting %s\n", buf);
+       pr_debug("Requesting %s\n", buf);
 
        error = request_firmware(&fw_lib, buf, &sst_drv_ctx->pci->dev);
        if (error) {
-               pr_err("sst: library load failed %d\n", error);
+               pr_err("library load failed %d\n", error);
                goto wake;
        }
        error = sst_validate_library(fw_lib, &lib->slot_info, &entry_point);
@@ -476,7 +479,7 @@ int sst_load_library(struct snd_sst_lib_download *lib, u8 ops)
                goto wake_free;
 
        /* lib is downloaded and init send alloc again */
-       pr_debug("sst: Library is downloaded now...\n");
+       pr_debug("Library is downloaded now...\n");
 wake_free:
        /* sst_wake_up_alloc_block(sst_drv_ctx, pvt_id, error, NULL); */
        release_firmware(fw_lib);
index 39c67fa0bd0cd2c580f13f134823e8054b238300..993c5333e9068c86c72edf1fb23032effe5d6210 100644 (file)
@@ -26,6 +26,8 @@
  *  This file defines all ipc functions
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/pci.h>
 #include <linux/firmware.h>
 #include <linux/sched.h>
@@ -75,16 +77,16 @@ void sst_post_message(struct work_struct *work)
        /*To check if LPE is in stalled state.*/
        retval = sst_stalled();
        if (retval < 0) {
-               pr_err("sst: in stalled state\n");
+               pr_err("in stalled state\n");
                return;
        }
-       pr_debug("sst: post message called\n");
+       pr_debug("post message called\n");
        spin_lock(&sst_drv_ctx->list_spin_lock);
 
        /* check list */
        if (list_empty(&sst_drv_ctx->ipc_dispatch_list)) {
                /* list is empty, mask imr */
-               pr_debug("sst: Empty msg queue... masking\n");
+               pr_debug("Empty msg queue... masking\n");
                imr.full = readl(sst_drv_ctx->shim + SST_IMRX);
                imr.part.done_interrupt = 1;
                /* dummy register for shim workaround */
@@ -97,7 +99,7 @@ void sst_post_message(struct work_struct *work)
        header.full = sst_shim_read(sst_drv_ctx->shim, SST_IPCX);
        if (header.part.busy) {
                /* busy, unmask */
-               pr_debug("sst: Busy not free... unmasking\n");
+               pr_debug("Busy not free... unmasking\n");
                imr.full = readl(sst_drv_ctx->shim + SST_IMRX);
                imr.part.done_interrupt = 0;
                /* dummy register for shim workaround */
@@ -109,8 +111,8 @@ void sst_post_message(struct work_struct *work)
        msg = list_entry(sst_drv_ctx->ipc_dispatch_list.next,
                        struct ipc_post, node);
        list_del(&msg->node);
-       pr_debug("sst: Post message: header = %x\n", msg->header.full);
-       pr_debug("sst: size: = %x\n", msg->header.part.data);
+       pr_debug("Post message: header = %x\n", msg->header.full);
+       pr_debug("size: = %x\n", msg->header.part.data);
        if (msg->header.part.large)
                memcpy_toio(sst_drv_ctx->mailbox + SST_MAILBOX_SEND,
                        msg->mailbox_data, msg->header.part.data);
@@ -166,13 +168,13 @@ int process_fw_init(struct sst_ipc_msg_wq *msg)
                (struct ipc_header_fw_init *)msg->mailbox;
        int retval = 0;
 
-       pr_debug("sst: *** FW Init msg came***\n");
+       pr_debug("*** FW Init msg came***\n");
        if (init->result) {
                mutex_lock(&sst_drv_ctx->sst_lock);
                sst_drv_ctx->sst_state = SST_ERROR;
                mutex_unlock(&sst_drv_ctx->sst_lock);
-               pr_debug("sst: FW Init failed, Error %x\n", init->result);
-               pr_err("sst: FW Init failed, Error %x\n", init->result);
+               pr_debug("FW Init failed, Error %x\n", init->result);
+               pr_err("FW Init failed, Error %x\n", init->result);
                retval = -init->result;
                return retval;
        }
@@ -181,11 +183,11 @@ int process_fw_init(struct sst_ipc_msg_wq *msg)
        mutex_lock(&sst_drv_ctx->sst_lock);
        sst_drv_ctx->sst_state = SST_FW_RUNNING;
        mutex_unlock(&sst_drv_ctx->sst_lock);
-       pr_debug("sst: FW Version %x.%x\n",
+       pr_debug("FW Version %x.%x\n",
                        init->fw_version.major, init->fw_version.minor);
-       pr_debug("sst: Build No %x Type %x\n",
+       pr_debug("Build No %x Type %x\n",
                        init->fw_version.build, init->fw_version.type);
-       pr_debug("sst:  Build date %s Time %s\n",
+       pr_debug(" Build date %s Time %s\n",
                        init->build_info.date, init->build_info.time);
        sst_wake_up_alloc_block(sst_drv_ctx, FW_DWNL_ID, retval, NULL);
        return retval;
@@ -204,19 +206,19 @@ void sst_process_message(struct work_struct *work)
                        container_of(work, struct sst_ipc_msg_wq, wq);
        int str_id = msg->header.part.str_id;
 
-       pr_debug("sst: IPC process for %x\n", msg->header.full);
+       pr_debug("IPC process for %x\n", msg->header.full);
 
        /* based on msg in list call respective handler */
        switch (msg->header.part.msg_id) {
        case IPC_SST_BUF_UNDER_RUN:
        case IPC_SST_BUF_OVER_RUN:
                if (sst_validate_strid(str_id)) {
-                       pr_err("sst:  stream id %d invalid\n", str_id);
+                       pr_err("stream id %d invalid\n", str_id);
                        break;
                }
-               pr_err("sst: Buffer under/overrun for%d\n",
+               pr_err("Buffer under/overrun for %d\n",
                                msg->header.part.str_id);
-               pr_err("sst: Got Underrun & not to send data...ignore\n");
+               pr_err("Got Underrun & not to send data...ignore\n");
                break;
 
        case IPC_SST_GET_PLAY_FRAMES:
@@ -224,35 +226,35 @@ void sst_process_message(struct work_struct *work)
                        struct stream_info *stream ;
 
                        if (sst_validate_strid(str_id)) {
-                               pr_err("sst: strid %d invalid\n", str_id);
+                               pr_err("strid %d invalid\n", str_id);
                                break;
                        }
                        /* call sst_play_frame */
                        stream = &sst_drv_ctx->streams[str_id];
-                       pr_debug("sst: sst_play_frames for %d\n",
+                       pr_debug("sst_play_frames for %d\n",
                                        msg->header.part.str_id);
                        mutex_lock(&sst_drv_ctx->streams[str_id].lock);
                        sst_play_frame(msg->header.part.str_id);
                        mutex_unlock(&sst_drv_ctx->streams[str_id].lock);
                        break;
                } else
-                       pr_err("sst: sst_play_frames for Penwell!!\n");
+                       pr_err("sst_play_frames for Penwell!!\n");
 
        case IPC_SST_GET_CAPT_FRAMES:
                if (sst_drv_ctx->pci_id == SST_MRST_PCI_ID) {
                        struct stream_info *stream;
                        /* call sst_capture_frame */
                        if (sst_validate_strid(str_id)) {
-                               pr_err("sst: str id %d invalid\n", str_id);
+                               pr_err("str id %d invalid\n", str_id);
                                break;
                        }
                        stream = &sst_drv_ctx->streams[str_id];
-                       pr_debug("sst: sst_capture_frames for %d\n",
+                       pr_debug("sst_capture_frames for %d\n",
                                        msg->header.part.str_id);
                        mutex_lock(&stream->lock);
                        if (stream->mmapped == false &&
                                        stream->src == SST_DRV) {
-                               pr_debug("sst: waking up block for copy.\n");
+                               pr_debug("waking up block for copy.\n");
                                stream->data_blk.ret_code = 0;
                                stream->data_blk.condition = true;
                                stream->data_blk.on = false;
@@ -261,11 +263,11 @@ void sst_process_message(struct work_struct *work)
                                sst_capture_frame(msg->header.part.str_id);
                        mutex_unlock(&stream->lock);
                } else
-                       pr_err("sst: sst_play_frames for Penwell!!\n");
+                       pr_err("sst_play_frames for Penwell!!\n");
                break;
 
        case IPC_IA_PRINT_STRING:
-               pr_debug("sst: been asked to print something by fw\n");
+               pr_debug("been asked to print something by fw\n");
                /* TBD */
                break;
 
@@ -277,12 +279,12 @@ void sst_process_message(struct work_struct *work)
 
        case IPC_SST_STREAM_PROCESS_FATAL_ERR:
                if (sst_validate_strid(str_id)) {
-                       pr_err("sst: stream id %d invalid\n", str_id);
+                       pr_err("stream id %d invalid\n", str_id);
                        break;
                }
-               pr_err("sst: codec fatal error %x stream %d...\n",
+               pr_err("codec fatal error %x stream %d...\n",
                                msg->header.full, msg->header.part.str_id);
-               pr_err("sst: Dropping the stream\n");
+               pr_err("Dropping the stream\n");
                sst_drop_stream(msg->header.part.str_id);
                break;
        case IPC_IA_LPE_GETTING_STALLED:
@@ -293,7 +295,7 @@ void sst_process_message(struct work_struct *work)
                break;
        default:
                /* Illegal case */
-               pr_err("sst: Unhandled msg %x header %x\n",
+               pr_err("Unhandled msg %x header %x\n",
                msg->header.part.msg_id, msg->header.full);
        }
        sst_clear_interrupt();
@@ -322,7 +324,7 @@ void sst_process_reply(struct work_struct *work)
                if (!msg->header.part.data) {
                        sst_drv_ctx->tgt_dev_blk.ret_code = 0;
                } else {
-                       pr_err("sst:  Msg %x reply error %x\n",
+                       pr_err(" Msg %x reply error %x\n",
                        msg->header.part.msg_id, msg->header.part.data);
                        sst_drv_ctx->tgt_dev_blk.ret_code =
                                        -msg->header.part.data;
@@ -340,7 +342,7 @@ void sst_process_reply(struct work_struct *work)
                        int major = fw_info->fw_version.major;
                        int minor = fw_info->fw_version.minor;
                        int build = fw_info->fw_version.build;
-                       pr_debug("sst: Msg succedded %x\n",
+                       pr_debug("Msg succeeded %x\n",
                                       msg->header.part.msg_id);
                        pr_debug("INFO: ***FW*** = %02d.%02d.%02d\n",
                                        major, minor, build);
@@ -349,13 +351,13 @@ void sst_process_reply(struct work_struct *work)
                                sizeof(struct snd_sst_fw_info));
                        sst_drv_ctx->fw_info_blk.ret_code = 0;
                } else {
-                       pr_err("sst:  Msg %x reply error %x\n",
+                       pr_err(" Msg %x reply error %x\n",
                        msg->header.part.msg_id, msg->header.part.data);
                        sst_drv_ctx->fw_info_blk.ret_code =
                                        -msg->header.part.data;
                }
                if (sst_drv_ctx->fw_info_blk.on == true) {
-                       pr_debug("sst: Memcopy succedded\n");
+                       pr_debug("Memcopy succeeded\n");
                        sst_drv_ctx->fw_info_blk.on = false;
                        sst_drv_ctx->fw_info_blk.condition = true;
                        wake_up(&sst_drv_ctx->wait_queue);
@@ -364,11 +366,11 @@ void sst_process_reply(struct work_struct *work)
        }
        case IPC_IA_SET_STREAM_MUTE:
                if (!msg->header.part.data) {
-                       pr_debug("sst: Msg succedded %x\n",
+                       pr_debug("Msg succeeded %x\n",
                                       msg->header.part.msg_id);
                        sst_drv_ctx->mute_info_blk.ret_code = 0;
                } else {
-                       pr_err("sst:  Msg %x reply error %x\n",
+                       pr_err(" Msg %x reply error %x\n",
                        msg->header.part.msg_id, msg->header.part.data);
                        sst_drv_ctx->mute_info_blk.ret_code =
                                        -msg->header.part.data;
@@ -382,11 +384,11 @@ void sst_process_reply(struct work_struct *work)
                break;
        case IPC_IA_SET_STREAM_VOL:
                if (!msg->header.part.data) {
-                       pr_debug("sst: Msg succedded %x\n",
+                       pr_debug("Msg succeeded %x\n",
                                       msg->header.part.msg_id);
                        sst_drv_ctx->vol_info_blk.ret_code = 0;
                } else {
-                       pr_err("sst:  Msg %x reply error %x\n",
+                       pr_err(" Msg %x reply error %x\n",
                                        msg->header.part.msg_id,
                        msg->header.part.data);
                        sst_drv_ctx->vol_info_blk.ret_code =
@@ -402,15 +404,15 @@ void sst_process_reply(struct work_struct *work)
                break;
        case IPC_IA_GET_STREAM_VOL:
                if (msg->header.part.large) {
-                       pr_debug("sst: Large Msg Received Successfully\n");
-                       pr_debug("sst: Msg succedded %x\n",
+                       pr_debug("Large Msg Received Successfully\n");
+                       pr_debug("Msg succeeded %x\n",
                                       msg->header.part.msg_id);
                        memcpy_fromio(sst_drv_ctx->vol_info_blk.data,
                                (void *) msg->mailbox,
                                sizeof(struct snd_sst_vol));
                        sst_drv_ctx->vol_info_blk.ret_code = 0;
                } else {
-                       pr_err("sst: Msg %x reply error %x\n",
+                       pr_err("Msg %x reply error %x\n",
                        msg->header.part.msg_id, msg->header.part.data);
                        sst_drv_ctx->vol_info_blk.ret_code =
                                        -msg->header.part.data;
@@ -424,18 +426,18 @@ void sst_process_reply(struct work_struct *work)
 
        case IPC_IA_GET_STREAM_PARAMS:
                if (sst_validate_strid(str_id)) {
-                       pr_err("sst: stream id %d invalid\n", str_id);
+                       pr_err("stream id %d invalid\n", str_id);
                        break;
                }
                str_info = &sst_drv_ctx->streams[str_id];
                if (msg->header.part.large) {
-                       pr_debug("sst: Get stream large success\n");
+                       pr_debug("Get stream large success\n");
                        memcpy_fromio(str_info->ctrl_blk.data,
                                ((void *)(msg->mailbox)),
                                sizeof(struct snd_sst_fw_get_stream_params));
                        str_info->ctrl_blk.ret_code = 0;
                } else {
-                       pr_err("sst: Msg %x reply error %x\n",
+                       pr_err("Msg %x reply error %x\n",
                                msg->header.part.msg_id, msg->header.part.data);
                        str_info->ctrl_blk.ret_code = -msg->header.part.data;
                }
@@ -447,19 +449,19 @@ void sst_process_reply(struct work_struct *work)
                break;
        case IPC_IA_DECODE_FRAMES:
                if (sst_validate_strid(str_id)) {
-                       pr_err("sst: stream id %d invalid\n", str_id);
+                       pr_err("stream id %d invalid\n", str_id);
                        break;
                }
                str_info = &sst_drv_ctx->streams[str_id];
                if (msg->header.part.large) {
-                       pr_debug("sst: Msg succedded %x\n",
+                       pr_debug("Msg succeeded %x\n",
                                       msg->header.part.msg_id);
                        memcpy_fromio(str_info->data_blk.data,
                                        ((void *)(msg->mailbox)),
                                        sizeof(struct snd_sst_decode_info));
                        str_info->data_blk.ret_code = 0;
                } else {
-                       pr_err("sst: Msg %x reply error %x\n",
+                       pr_err("Msg %x reply error %x\n",
                                msg->header.part.msg_id, msg->header.part.data);
                        str_info->data_blk.ret_code = -msg->header.part.data;
                }
@@ -471,17 +473,17 @@ void sst_process_reply(struct work_struct *work)
                break;
        case IPC_IA_DRAIN_STREAM:
                if (sst_validate_strid(str_id)) {
-                       pr_err("sst: stream id %d invalid\n", str_id);
+                       pr_err("stream id %d invalid\n", str_id);
                        break;
                }
                str_info = &sst_drv_ctx->streams[str_id];
                if (!msg->header.part.data) {
-                       pr_debug("sst: Msg succedded %x\n",
+                       pr_debug("Msg succeeded %x\n",
                                        msg->header.part.msg_id);
                        str_info->ctrl_blk.ret_code = 0;
 
                } else {
-                       pr_err("sst:  Msg %x reply error %x\n",
+                       pr_err(" Msg %x reply error %x\n",
                                msg->header.part.msg_id, msg->header.part.data);
                        str_info->ctrl_blk.ret_code = -msg->header.part.data;
 
@@ -496,7 +498,7 @@ void sst_process_reply(struct work_struct *work)
 
        case IPC_IA_DROP_STREAM:
                if (sst_validate_strid(str_id)) {
-                       pr_err("sst: str id %d invalid\n", str_id);
+                       pr_err("str id %d invalid\n", str_id);
                        break;
                }
                str_info = &sst_drv_ctx->streams[str_id];
@@ -504,12 +506,12 @@ void sst_process_reply(struct work_struct *work)
                        struct snd_sst_drop_response *drop_resp =
                                (struct snd_sst_drop_response *)msg->mailbox;
 
-                       pr_debug("sst: Drop ret bytes %x\n", drop_resp->bytes);
+                       pr_debug("Drop ret bytes %x\n", drop_resp->bytes);
 
                        str_info->curr_bytes = drop_resp->bytes;
                        str_info->ctrl_blk.ret_code =  0;
                } else {
-                       pr_err("sst:  Msg %x reply error %x\n",
+                       pr_err(" Msg %x reply error %x\n",
                                msg->header.part.msg_id, msg->header.part.data);
                        str_info->ctrl_blk.ret_code = -msg->header.part.data;
                }
@@ -521,10 +523,10 @@ void sst_process_reply(struct work_struct *work)
                break;
        case IPC_IA_ENABLE_RX_TIME_SLOT:
                if (!msg->header.part.data) {
-                       pr_debug("sst: RX_TIME_SLOT success\n");
+                       pr_debug("RX_TIME_SLOT success\n");
                        sst_drv_ctx->hs_info_blk.ret_code = 0;
                } else {
-                       pr_err("sst:  Msg %x reply error %x\n",
+                       pr_err(" Msg %x reply error %x\n",
                                msg->header.part.msg_id,
                                msg->header.part.data);
                        sst_drv_ctx->hs_info_blk.ret_code =
@@ -541,17 +543,17 @@ void sst_process_reply(struct work_struct *work)
        case IPC_IA_SET_STREAM_PARAMS:
                str_info = &sst_drv_ctx->streams[str_id];
                if (!msg->header.part.data) {
-                       pr_debug("sst: Msg succedded %x\n",
+                       pr_debug("Msg succeeded %x\n",
                                        msg->header.part.msg_id);
                        str_info->ctrl_blk.ret_code = 0;
                } else {
-                       pr_err("sst:  Msg %x reply error %x\n",
+                       pr_err(" Msg %x reply error %x\n",
                                        msg->header.part.msg_id,
                                        msg->header.part.data);
                        str_info->ctrl_blk.ret_code = -msg->header.part.data;
                }
                if (sst_validate_strid(str_id)) {
-                       pr_err("sst:  stream id %d invalid\n", str_id);
+                       pr_err(" stream id %d invalid\n", str_id);
                        break;
                }
 
@@ -564,9 +566,9 @@ void sst_process_reply(struct work_struct *work)
 
        case IPC_IA_FREE_STREAM:
                if (!msg->header.part.data) {
-                       pr_debug("sst: Stream %d freed\n", str_id);
+                       pr_debug("Stream %d freed\n", str_id);
                } else {
-                       pr_err("sst: Free for %d ret error %x\n",
+                       pr_err("Free for %d ret error %x\n",
                                       str_id, msg->header.part.data);
                }
                break;
@@ -575,7 +577,7 @@ void sst_process_reply(struct work_struct *work)
                struct snd_sst_alloc_response *resp =
                                (struct snd_sst_alloc_response *)msg->mailbox;
                if (resp->str_type.result)
-                       pr_err("sst: error alloc stream = %x\n",
+                       pr_err("error alloc stream = %x\n",
                                       resp->str_type.result);
                sst_alloc_stream_response(str_id, resp);
                break;
@@ -584,21 +586,21 @@ void sst_process_reply(struct work_struct *work)
        case IPC_IA_PLAY_FRAMES:
        case IPC_IA_CAPT_FRAMES:
                if (sst_validate_strid(str_id)) {
-                       pr_err("sst: stream id %d invalid\n" , str_id);
+                       pr_err("stream id %d invalid\n", str_id);
                        break;
                }
-               pr_debug("sst: Ack for play/capt frames recived\n");
+               pr_debug("Ack for play/capt frames received\n");
                break;
 
        case IPC_IA_PREP_LIB_DNLD: {
                struct snd_sst_str_type *str_type =
                        (struct snd_sst_str_type *)msg->mailbox;
-               pr_debug("sst: Prep Lib download %x\n",
+               pr_debug("Prep Lib download %x\n",
                                msg->header.part.msg_id);
                if (str_type->result)
-                       pr_err("sst: Prep lib download %x\n", str_type->result);
+                       pr_err("Prep lib download %x\n", str_type->result);
                else
-                       pr_debug("sst: Can download codec now...\n");
+                       pr_debug("Can download codec now...\n");
                sst_wake_up_alloc_block(sst_drv_ctx, str_id,
                                str_type->result, NULL);
                break;
@@ -609,12 +611,12 @@ void sst_process_reply(struct work_struct *work)
                        (struct snd_sst_lib_download_info *)msg->mailbox;
                int retval = resp->result;
 
-               pr_debug("sst: Lib downloaded %x\n", msg->header.part.msg_id);
+               pr_debug("Lib downloaded %x\n", msg->header.part.msg_id);
                if (resp->result) {
-                       pr_err("sst: err in lib dload %x\n", resp->result);
+                       pr_err("err in lib dload %x\n", resp->result);
                } else {
-                       pr_debug("sst: Codec download complete...\n");
-                       pr_debug("sst: codec Type %d Ver %d Built %s: %s\n",
+                       pr_debug("Codec download complete...\n");
+                       pr_debug("codec Type %d Ver %d Built %s: %s\n",
                                resp->dload_lib.lib_info.lib_type,
                                resp->dload_lib.lib_info.lib_version,
                                resp->dload_lib.lib_info.b_date,
@@ -639,17 +641,17 @@ void sst_process_reply(struct work_struct *work)
        case IPC_IA_GET_FW_BUILD_INF: {
                struct sst_fw_build_info *build =
                        (struct sst_fw_build_info *)msg->mailbox;
-               pr_debug("sst: Build date:%sTime:%s", build->date, build->time);
+               pr_debug("Build date:%sTime:%s", build->date, build->time);
                break;
        }
        case IPC_IA_SET_PMIC_TYPE:
                break;
        case IPC_IA_START_STREAM:
-               pr_debug("sst: reply for START STREAM %x\n", msg->header.full);
+               pr_debug("reply for START STREAM %x\n", msg->header.full);
                break;
        default:
                /* Illegal case */
-               pr_err("sst: process reply:default = %x\n", msg->header.full);
+               pr_err("process reply:default = %x\n", msg->header.full);
        }
        sst_clear_interrupt();
        return;
index 6487e192bf937cdab3400c60f7816fae4b2924f8..01f8c3b1cf74f1a68bbad8b99139a742f1b12ce6 100644 (file)
@@ -29,6 +29,8 @@
  *  This file contains all private functions
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/pci.h>
 #include <linux/fs.h>
 #include <linux/firmware.h>
@@ -60,7 +62,7 @@ int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx)
                }
        }
        if (i == MAX_ACTIVE_STREAM) {
-               pr_err("sst: max alloc_stream reached");
+               pr_err("max alloc_stream reached\n");
                i = -EBUSY; /* active stream limit reached */
        }
        return i;
@@ -84,14 +86,14 @@ int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx,
                                block->condition)) {
                /* event wake */
                if (block->ret_code < 0) {
-                       pr_err("sst: stream failed %d\n", block->ret_code);
+                       pr_err("stream failed %d\n", block->ret_code);
                        retval = -EBUSY;
                } else {
-                       pr_debug("sst: event up\n");
+                       pr_debug("event up\n");
                        retval = 0;
                }
        } else {
-               pr_err("sst: signal interrupted\n");
+               pr_err("signal interrupted\n");
                retval = -EINTR;
        }
        return retval;
@@ -115,18 +117,18 @@ int sst_wait_interruptible_timeout(
 {
        int retval = 0;
 
-       pr_debug("sst: sst_wait_interruptible_timeout - waiting....\n");
+       pr_debug("sst_wait_interruptible_timeout - waiting....\n");
        if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue,
                                                block->condition,
                                                msecs_to_jiffies(timeout))) {
                if (block->ret_code < 0)
-                       pr_err("sst: stream failed %d\n", block->ret_code);
+                       pr_err("stream failed %d\n", block->ret_code);
                else
-                       pr_debug("sst: event up\n");
+                       pr_debug("event up\n");
                retval = block->ret_code;
        } else {
                block->on = false;
-               pr_err("sst: timeout occured...\n");
+               pr_err("timeout occurred...\n");
                /*setting firmware state as uninit so that the
                firmware will get re-downloaded on next request
                this is because firmare not responding for 5 sec
@@ -156,18 +158,18 @@ int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx,
        /* NOTE:
        Observed that FW processes the alloc msg and replies even
        before the alloc thread has finished execution */
-       pr_debug("sst: waiting for %x, condition %x\n",
+       pr_debug("waiting for %x, condition %x\n",
                       block->sst_id, block->ops_block.condition);
        if (wait_event_interruptible_timeout(sst_drv_ctx->wait_queue,
                                block->ops_block.condition,
                                msecs_to_jiffies(SST_BLOCK_TIMEOUT))) {
                /* event wake */
-               pr_debug("sst: Event wake %x\n", block->ops_block.condition);
-               pr_debug("sst: message ret: %d\n", block->ops_block.ret_code);
+               pr_debug("Event wake %x\n", block->ops_block.condition);
+               pr_debug("message ret: %d\n", block->ops_block.ret_code);
                retval = block->ops_block.ret_code;
        } else {
                block->ops_block.on = false;
-               pr_err("sst: Wait timed-out %x\n", block->ops_block.condition);
+               pr_err("Wait timed-out %x\n", block->ops_block.condition);
                /* settign firmware state as uninit so that the
                firmware will get redownloaded on next request
                this is because firmare not responding for 5 sec
@@ -192,14 +194,14 @@ int sst_create_large_msg(struct ipc_post **arg)
 
        msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC);
        if (!msg) {
-               pr_err("sst: kzalloc msg failed\n");
+               pr_err("kzalloc msg failed\n");
                return -ENOMEM;
        }
 
        msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC);
        if (!msg->mailbox_data) {
                kfree(msg);
-               pr_err("sst: kzalloc mailbox_data failed");
+               pr_err("kzalloc mailbox_data failed");
                return -ENOMEM;
        };
        *arg = msg;
@@ -219,7 +221,7 @@ int sst_create_short_msg(struct ipc_post **arg)
 
        msg = kzalloc(sizeof(*msg), GFP_ATOMIC);
        if (!msg) {
-               pr_err("sst: kzalloc msg failed\n");
+               pr_err("kzalloc msg failed\n");
                return -ENOMEM;
        }
        msg->mailbox_data = NULL;
@@ -290,10 +292,10 @@ int sst_enable_rx_timeslot(int status)
        struct ipc_post *msg = NULL;
 
        if (sst_create_short_msg(&msg)) {
-               pr_err("sst: mem allocation failed\n");
+               pr_err("mem allocation failed\n");
                        return -ENOMEM;
        }
-       pr_debug("sst: ipc message sending: ENABLE_RX_TIME_SLOT\n");
+       pr_debug("ipc message sending: ENABLE_RX_TIME_SLOT\n");
        sst_fill_header(&msg->header, IPC_IA_ENABLE_RX_TIME_SLOT, 0, 0);
        msg->header.part.data = status;
        sst_drv_ctx->hs_info_blk.condition = false;
index b2c4b7067da0215db08b13de609710553aa9b645..8f6e1005371dfd8480309d438f8c4278f7dd92eb 100644 (file)
@@ -26,6 +26,8 @@
  *  This file contains the stream operations of SST driver
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/pci.h>
 #include <linux/firmware.h>
 #include <linux/sched.h>
@@ -46,7 +48,7 @@
 int sst_check_device_type(u32 device, u32 num_chan, u32 *pcm_slot)
 {
        if (device >= MAX_NUM_STREAMS) {
-               pr_debug("sst: device type invalid %d\n", device);
+               pr_debug("device type invalid %d\n", device);
                return -EINVAL;
        }
        if (sst_drv_ctx->streams[device].status == STREAM_UN_INIT) {
@@ -71,15 +73,15 @@ int sst_check_device_type(u32 device, u32 num_chan, u32 *pcm_slot)
                else if (device == SND_SST_DEVICE_CAPTURE && num_chan == 4)
                        *pcm_slot = 0x0F;
                else {
-                       pr_debug("sst: No condition satisfied.. ret err\n");
+                       pr_debug("No condition satisfied.. ret err\n");
                        return -EINVAL;
                }
        } else {
-               pr_debug("sst: this stream state is not uni-init, is %d\n",
+               pr_debug("this stream state is not uni-init, is %d\n",
                                sst_drv_ctx->streams[device].status);
                return -EBADRQC;
        }
-       pr_debug("sst: returning slot %x\n", *pcm_slot);
+       pr_debug("returning slot %x\n", *pcm_slot);
        return 0;
 }
 /**
@@ -96,7 +98,7 @@ static unsigned int get_mrst_stream_id(void)
                if (sst_drv_ctx->streams[i].status == STREAM_UN_INIT)
                        return i;
        }
-       pr_debug("sst: Didnt find empty stream for mrst\n");
+       pr_debug("Didnt find empty stream for mrst\n");
        return -EBUSY;
 }
 
@@ -305,7 +307,7 @@ int sst_pause_stream(int str_id)
                if (str_info->prev == STREAM_UN_INIT)
                        return -EBADRQC;
                if (str_info->ctrl_blk.on == true) {
-                       pr_err("SST ERR: control path is in use\n ");
+                       pr_err("SST ERR: control path is in use\n");
                        return -EINVAL;
                }
                if (sst_create_short_msg(&msg))
@@ -333,7 +335,7 @@ int sst_pause_stream(int str_id)
                }
        } else {
                retval = -EBADRQC;
-               pr_err("SST ERR:BADQRC for stream\n ");
+               pr_err("SST ERR: BADQRC for stream\n");
        }
 
        return retval;
@@ -468,7 +470,7 @@ int sst_drop_stream(int str_id)
                }
        } else {
                retval = -EBADRQC;
-               pr_err("SST ERR:BADQRC for stream\n");
+               pr_err("SST ERR: BADQRC for stream\n");
        }
        return retval;
 }
index fbae39fda5c0307151024edd92bc7c65523bb9f0..d4e94f1ec83097ff514881c675c9ca34b45f135d 100644 (file)
@@ -26,6 +26,8 @@
  *  This file contains the stream operations of SST driver
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/pci.h>
 #include <linux/syscalls.h>
 #include <linux/firmware.h>
@@ -53,7 +55,7 @@ int sst_get_stream_params(int str_id,
        struct stream_info *str_info;
        struct snd_sst_fw_get_stream_params *fw_params;
 
-       pr_debug("sst: get_stream for %d\n", str_id);
+       pr_debug("get_stream for %d\n", str_id);
        retval = sst_validate_strid(str_id);
        if (retval)
                return retval;
@@ -61,16 +63,16 @@ int sst_get_stream_params(int str_id,
        str_info = &sst_drv_ctx->streams[str_id];
        if (str_info->status != STREAM_UN_INIT) {
                if (str_info->ctrl_blk.on == true) {
-                       pr_err("sst: control path in use\n");
+                       pr_err("control path in use\n");
                        return -EINVAL;
                }
                if (sst_create_short_msg(&msg)) {
-                       pr_err("sst: message creation failed\n");
+                       pr_err("message creation failed\n");
                        return -ENOMEM;
                }
                fw_params = kzalloc(sizeof(*fw_params), GFP_ATOMIC);
                if (!fw_params) {
-                       pr_err("sst: mem allcoation failed\n ");
+                       pr_err("mem allocation failed\n");
                        kfree(msg);
                        return -ENOMEM;
                }
@@ -104,7 +106,7 @@ int sst_get_stream_params(int str_id,
                get_params->codec_params.stream_type = str_info->str_type;
                kfree(fw_params);
        } else {
-               pr_debug("sst: Stream is not in the init state\n");
+               pr_debug("Stream is not in the init state\n");
        }
        return retval;
 }
@@ -125,17 +127,17 @@ int sst_set_stream_param(int str_id, struct snd_sst_params *str_param)
 
        BUG_ON(!str_param);
        if (sst_drv_ctx->streams[str_id].ops != str_param->ops) {
-               pr_err("sst: Invalid operation\n");
+               pr_err("Invalid operation\n");
                return -EINVAL;
        }
        retval = sst_validate_strid(str_id);
        if (retval)
                return retval;
-       pr_debug("sst: set_stream for %d\n", str_id);
+       pr_debug("set_stream for %d\n", str_id);
        str_info =  &sst_drv_ctx->streams[str_id];
        if (sst_drv_ctx->streams[str_id].status == STREAM_INIT) {
                if (str_info->ctrl_blk.on == true) {
-                       pr_err("sst: control path in use\n");
+                       pr_err("control path in use\n");
                        return -EAGAIN;
                }
                if (sst_create_large_msg(&msg))
@@ -163,7 +165,7 @@ int sst_set_stream_param(int str_id, struct snd_sst_params *str_param)
                }
        } else {
                retval = -EBADRQC;
-               pr_err("sst: BADQRC for stream\n");
+               pr_err("BADQRC for stream\n");
        }
        return retval;
 }
@@ -183,7 +185,7 @@ int sst_get_vol(struct snd_sst_vol *get_vol)
        struct snd_sst_vol *fw_get_vol;
        int str_id = get_vol->stream_id;
 
-       pr_debug("sst: get vol called\n");
+       pr_debug("get vol called\n");
 
        if (sst_create_short_msg(&msg))
                return -ENOMEM;
@@ -195,7 +197,7 @@ int sst_get_vol(struct snd_sst_vol *get_vol)
        sst_drv_ctx->vol_info_blk.on = true;
        fw_get_vol = kzalloc(sizeof(*fw_get_vol), GFP_ATOMIC);
        if (!fw_get_vol) {
-               pr_err("sst: mem allocation failed\n");
+               pr_err("mem allocation failed\n");
                kfree(msg);
                return -ENOMEM;
        }
@@ -209,10 +211,10 @@ int sst_get_vol(struct snd_sst_vol *get_vol)
        if (retval)
                retval = -EIO;
        else {
-               pr_debug("sst: stream id %d\n", fw_get_vol->stream_id);
-               pr_debug("sst: volume %d\n", fw_get_vol->volume);
-               pr_debug("sst: ramp duration %d\n", fw_get_vol->ramp_duration);
-               pr_debug("sst: ramp_type %d\n", fw_get_vol->ramp_type);
+               pr_debug("stream id %d\n", fw_get_vol->stream_id);
+               pr_debug("volume %d\n", fw_get_vol->volume);
+               pr_debug("ramp duration %d\n", fw_get_vol->ramp_duration);
+               pr_debug("ramp_type %d\n", fw_get_vol->ramp_type);
                memcpy(get_vol, fw_get_vol, sizeof(*fw_get_vol));
        }
        return retval;
@@ -231,10 +233,10 @@ int sst_set_vol(struct snd_sst_vol *set_vol)
        int retval = 0;
        struct ipc_post *msg = NULL;
 
-       pr_debug("sst: set vol called\n");
+       pr_debug("set vol called\n");
 
        if (sst_create_large_msg(&msg)) {
-               pr_err("sst: message creation failed\n");
+               pr_err("message creation failed\n");
                return -ENOMEM;
        }
        sst_fill_header(&msg->header, IPC_IA_SET_STREAM_VOL, 1,
@@ -254,7 +256,7 @@ int sst_set_vol(struct snd_sst_vol *set_vol)
        retval = sst_wait_interruptible_timeout(sst_drv_ctx,
                        &sst_drv_ctx->vol_info_blk, SST_BLOCK_TIMEOUT);
        if (retval) {
-               pr_err("sst: error in set_vol = %d\n", retval);
+               pr_err("error in set_vol = %d\n", retval);
                retval = -EIO;
        }
        return retval;
@@ -273,10 +275,10 @@ int sst_set_mute(struct snd_sst_mute *set_mute)
        int retval = 0;
        struct ipc_post *msg = NULL;
 
-       pr_debug("sst: set mute called\n");
+       pr_debug("set mute called\n");
 
        if (sst_create_large_msg(&msg)) {
-               pr_err("sst: message creation failed\n");
+               pr_err("message creation failed\n");
                return -ENOMEM;
        }
        sst_fill_header(&msg->header, IPC_IA_SET_STREAM_MUTE, 1,
@@ -297,7 +299,7 @@ int sst_set_mute(struct snd_sst_mute *set_mute)
        retval = sst_wait_interruptible_timeout(sst_drv_ctx,
                        &sst_drv_ctx->mute_info_blk, SST_BLOCK_TIMEOUT);
        if (retval) {
-               pr_err("sst: error in set_mute = %d\n", retval);
+               pr_err("error in set_mute = %d\n", retval);
                retval = -EIO;
        }
        return retval;
@@ -358,20 +360,20 @@ int sst_parse_target(struct snd_sst_slot_info *slot)
                slot->device_type == SND_SST_DEVICE_PCM) {
                        retval = sst_activate_target(slot);
                        if (retval)
-                               pr_err("sst: SST_Activate_target_fail\n");
+                               pr_err("SST_Activate_target_fail\n");
                        else
-                               pr_err("sst: SST_Activate_target_pass\n");
+                               pr_err("SST_Activate_target_pass\n");
                return retval;
        } else if (slot->action == SND_SST_PORT_PREPARE &&
                        slot->device_type == SND_SST_DEVICE_PCM) {
                                retval = sst_prepare_target(slot);
                        if (retval)
-                               pr_err("sst: SST_prepare_target_fail\n");
+                               pr_err("SST_prepare_target_fail\n");
                        else
-                               pr_err("sst: SST_prepare_target_pass\n");
+                               pr_err("SST_prepare_target_pass\n");
                        return retval;
        } else {
-               pr_err("sst: slot_action : %d, device_type: %d\n",
+               pr_err("slot_action : %d, device_type: %d\n",
                                slot->action, slot->device_type);
                return retval;
        }
@@ -383,7 +385,7 @@ int sst_send_target(struct snd_sst_target_device *target)
        struct ipc_post *msg;
 
        if (sst_create_large_msg(&msg)) {
-               pr_err("sst: message creation failed\n");
+               pr_err("message creation failed\n");
                return -ENOMEM;
        }
        sst_fill_header(&msg->header, IPC_IA_TARGET_DEV_SELECT, 1, 0);
@@ -399,11 +401,11 @@ int sst_send_target(struct snd_sst_target_device *target)
        list_add_tail(&msg->node, &sst_drv_ctx->ipc_dispatch_list);
        spin_unlock(&sst_drv_ctx->list_spin_lock);
        sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
-       pr_debug("sst: message sent- waiting\n");
+       pr_debug("message sent- waiting\n");
        retval = sst_wait_interruptible_timeout(sst_drv_ctx,
                        &sst_drv_ctx->tgt_dev_blk, TARGET_DEV_BLOCK_TIMEOUT);
        if (retval)
-               pr_err("sst: target device ipc failed = 0x%x\n", retval);
+               pr_err("target device ipc failed = 0x%x\n", retval);
        return retval;
 
 }
@@ -439,7 +441,7 @@ int sst_target_device_validate(struct snd_sst_target_device *target)
                                        goto err;
                        } else {
 err:
-                               pr_err("sst: i/p params incorrect\n");
+                               pr_err("i/p params incorrect\n");
                                return -EINVAL;
                        }
                }
@@ -460,15 +462,15 @@ int sst_target_device_select(struct snd_sst_target_device *target)
 {
        int retval, i, prepare_count = 0;
 
-       pr_debug("sst: Target Device Select\n");
+       pr_debug("Target Device Select\n");
 
        if (target->device_route < 0 || target->device_route > 2) {
-               pr_err("sst: device route is invalid\n");
+               pr_err("device route is invalid\n");
                return -EINVAL;
        }
 
        if (target->device_route != 0) {
-               pr_err("sst: Unsupported config\n");
+               pr_err("Unsupported config\n");
                return -EIO;
        }
        retval = sst_target_device_validate(target);
@@ -480,18 +482,18 @@ int sst_target_device_select(struct snd_sst_target_device *target)
                return retval;
        for (i = 0; i < SST_MAX_TARGET_DEVICES; i++) {
                if (target->devices[i].action == SND_SST_PORT_ACTIVATE) {
-                       pr_debug("sst: activate called in %d\n", i);
+                       pr_debug("activate called in %d\n", i);
                        retval = sst_parse_target(&target->devices[i]);
                        if (retval)
                                return retval;
                } else if (target->devices[i].action == SND_SST_PORT_PREPARE) {
-                       pr_debug("sst: PREPARE in %d, Forwading\n", i);
+                       pr_debug("PREPARE in %d, Forwarding\n", i);
                        retval = sst_parse_target(&target->devices[i]);
                        if (retval) {
-                               pr_err("sst: Parse Target fail %d", retval);
+                               pr_err("Parse Target fail %d\n", retval);
                                return retval;
                        }
-                       pr_debug("sst: Parse Target successful %d", retval);
+                       pr_debug("Parse Target successful %d\n", retval);
                        if (target->devices[i].device_type ==
                                                SND_SST_DEVICE_PCM)
                                prepare_count++;
@@ -512,11 +514,11 @@ static inline int sst_get_RAR(struct RAR_buffer *buffers, int count)
        rar_status = rar_handle_to_bus(buffers, count);
 
        if (count != rar_status) {
-               pr_err("sst: The rar CALL Failed");
+               pr_err("The rar CALL Failed");
                retval = -EIO;
        }
        if (buffers->info.type != RAR_TYPE_AUDIO) {
-               pr_err("sst: Invalid RAR type\n");
+               pr_err("Invalid RAR type\n");
                return -EINVAL;
        }
        return retval;
@@ -539,10 +541,10 @@ static int sst_create_sg_list(struct stream_info *stream,
                if (kbufs->in_use == false) {
 #ifdef CONFIG_MRST_RAR_HANDLER
                        if (stream->ops == STREAM_OPS_PLAYBACK_DRM) {
-                               pr_debug("sst: DRM playback handling\n");
+                               pr_debug("DRM playback handling\n");
                                rar_buffers.info.handle = (__u32)kbufs->addr;
                                rar_buffers.info.size = kbufs->size;
-                               pr_debug("sst: rar handle 0x%x size=0x%x",
+                               pr_debug("rar handle 0x%x size=0x%x\n",
                                        rar_buffers.info.handle,
                                        rar_buffers.info.size);
                                retval =  sst_get_RAR(&rar_buffers, 1);
@@ -552,7 +554,7 @@ static int sst_create_sg_list(struct stream_info *stream,
                                sg_list->addr[i].addr = rar_buffers.bus_address;
                                /* rar_buffers.info.size; */
                                sg_list->addr[i].size = (__u32)kbufs->size;
-                               pr_debug("sst: phyaddr[%d] 0x%x Size:0x%x\n"
+                               pr_debug("phyaddr[%d] 0x%x Size:0x%x\n"
                                        , i, sg_list->addr[i].addr,
                                        sg_list->addr[i].size);
                        }
@@ -562,7 +564,7 @@ static int sst_create_sg_list(struct stream_info *stream,
                                        virt_to_phys((void *)
                                                kbufs->addr + kbufs->offset);
                                sg_list->addr[i].size = kbufs->size;
-                               pr_debug("sst: phyaddr[%d]:0x%x Size:0x%x\n"
+                               pr_debug("phyaddr[%d]:0x%x Size:0x%x\n"
                                , i , sg_list->addr[i].addr, kbufs->size);
                        }
                        stream->curr_bytes += sg_list->addr[i].size;
@@ -574,7 +576,7 @@ static int sst_create_sg_list(struct stream_info *stream,
        }
 
        sg_list->num_entries = i;
-       pr_debug("sst:sg list entries = %d\n", sg_list->num_entries);
+       pr_debug("sg list entries = %d\n", sg_list->num_entries);
        return i;
 }
 
@@ -595,7 +597,7 @@ int sst_play_frame(int str_id)
        struct sst_stream_bufs *kbufs = NULL, *_kbufs;
        struct stream_info *stream;
 
-       pr_debug("sst: play frame for %d\n", str_id);
+       pr_debug("play frame for %d\n", str_id);
        retval = sst_validate_strid(str_id);
        if (retval)
                return retval;
@@ -615,14 +617,14 @@ int sst_play_frame(int str_id)
        stream->curr_bytes = 0;
        if (list_empty(&stream->bufs)) {
                /* no user buffer available */
-               pr_debug("sst: Null buffer stream status %d\n", stream->status);
+               pr_debug("Null buffer stream status %d\n", stream->status);
                stream->prev = stream->status;
                stream->status = STREAM_INIT;
-               pr_debug("sst:new stream status = %d\n", stream->status);
+               pr_debug("new stream status = %d\n", stream->status);
                if (stream->need_draining == true) {
-                       pr_debug("sst:draining stream\n");
+                       pr_debug("draining stream\n");
                        if (sst_create_short_msg(&msg)) {
-                               pr_err("sst: mem alloc failed\n");
+                               pr_err("mem allocation failed\n");
                                return -ENOMEM;
                        }
                        sst_fill_header(&msg->header, IPC_IA_DRAIN_STREAM,
@@ -633,7 +635,7 @@ int sst_play_frame(int str_id)
                        spin_unlock(&sst_drv_ctx->list_spin_lock);
                        sst_post_message(&sst_drv_ctx->ipc_post_msg_wq);
                } else if (stream->data_blk.on == true) {
-                       pr_debug("sst:user list empty.. wake\n");
+                       pr_debug("user list empty.. wake\n");
                        /* unblock */
                        stream->data_blk.ret_code = 0;
                        stream->data_blk.condition = true;
@@ -678,7 +680,7 @@ int sst_capture_frame(int str_id)
        struct stream_info *stream;
 
 
-       pr_debug("sst:capture frame for %d\n", str_id);
+       pr_debug("capture frame for %d\n", str_id);
        retval = sst_validate_strid(str_id);
        if (retval)
                return retval;
@@ -688,19 +690,19 @@ int sst_capture_frame(int str_id)
                if (kbufs->in_use == true) {
                        list_del(&kbufs->node);
                        kfree(kbufs);
-                       pr_debug("sst:del node\n");
+                       pr_debug("del node\n");
                }
        }
        if (list_empty(&stream->bufs)) {
                /* no user buffer available */
-               pr_debug("sst:Null buffer!!!!stream status %d\n",
+               pr_debug("Null buffer!!!!stream status %d\n",
                               stream->status);
                stream->prev = stream->status;
                stream->status = STREAM_INIT;
-               pr_debug("sst:new stream status = %d\n",
+               pr_debug("new stream status = %d\n",
                               stream->status);
                if (stream->data_blk.on == true) {
-                       pr_debug("sst:user list empty.. wake\n");
+                       pr_debug("user list empty.. wake\n");
                        /* unblock */
                        stream->data_blk.ret_code = 0;
                        stream->data_blk.condition = true;
@@ -731,7 +733,7 @@ int sst_capture_frame(int str_id)
        stream->cumm_bytes += stream->curr_bytes;
        stream->curr_bytes = 0;
 
-    pr_debug("sst:Cum bytes  = %d\n", stream->cumm_bytes);
+    pr_debug("Cum bytes  = %d\n", stream->cumm_bytes);
        return 0;
 }
 
@@ -743,7 +745,7 @@ static unsigned int calculate_min_size(struct snd_sst_buffs *bufs)
                if (bufs->buff_entry[i].size < min_val)
                        min_val = bufs->buff_entry[i].size;
        }
-       pr_debug("sst:min_val = %d\n", min_val);
+       pr_debug("min_val = %d\n", min_val);
        return min_val;
 }
 
@@ -754,7 +756,7 @@ static unsigned int calculate_max_size(struct snd_sst_buffs *bufs)
                if (bufs->buff_entry[i].size > max_val)
                        max_val = bufs->buff_entry[i].size;
        }
-       pr_debug("sst:max_val = %d\n", max_val);
+       pr_debug("max_val = %d\n", max_val);
        return max_val;
 }
 
@@ -773,7 +775,7 @@ static int sst_allocate_decode_buf(struct stream_info *str_info,
                        if (dbufs->ibufs->entries == dbufs->obufs->entries)
                                return 0;
                        else {
-                               pr_err("sst: RAR entries dont match\n");
+                               pr_err("RAR entries dont match\n");
                                 return -EINVAL;
                        }
                } else
@@ -783,26 +785,26 @@ static int sst_allocate_decode_buf(struct stream_info *str_info,
        }
 #endif
        if (!str_info->decode_ibuf) {
-               pr_debug("sst:no i/p buffers, trying full size\n");
+               pr_debug("no i/p buffers, trying full size\n");
                str_info->decode_isize = cum_input_given;
                str_info->decode_ibuf = kzalloc(str_info->decode_isize,
                                                GFP_KERNEL);
                str_info->idecode_alloc = str_info->decode_isize;
        }
        if (!str_info->decode_ibuf) {
-               pr_debug("sst:buff alloc failed, try max size\n");
+               pr_debug("buff alloc failed, try max size\n");
                str_info->decode_isize = calculate_max_size(dbufs->ibufs);
                str_info->decode_ibuf = kzalloc(
                                str_info->decode_isize, GFP_KERNEL);
                str_info->idecode_alloc = str_info->decode_isize;
        }
        if (!str_info->decode_ibuf) {
-               pr_debug("sst:buff alloc failed, try min size\n");
+               pr_debug("buff alloc failed, try min size\n");
                str_info->decode_isize = calculate_min_size(dbufs->ibufs);
                str_info->decode_ibuf = kzalloc(str_info->decode_isize,
                                                GFP_KERNEL);
                if (!str_info->decode_ibuf) {
-                       pr_err("sst: mem allocation failed\n");
+                       pr_err("mem allocation failed\n");
                        return -ENOMEM;
                }
                str_info->idecode_alloc = str_info->decode_isize;
@@ -820,7 +822,7 @@ static int sst_send_decode_mess(int str_id, struct stream_info *str_info,
        struct ipc_post *msg = NULL;
        int retval = 0;
 
-       pr_debug("SST DBGsst_set_mute:called\n");
+       pr_debug("SST DBG:sst_set_mute:called\n");
 
        if (str_info->decode_ibuf_type == SST_BUF_RAR) {
 #ifdef CONFIG_MRST_RAR_HANDLER
@@ -857,7 +859,7 @@ static int sst_send_decode_mess(int str_id, struct stream_info *str_info,
        dec_info->input_bytes_consumed = 0;
        dec_info->output_bytes_produced = 0;
        if (sst_create_large_msg(&msg)) {
-               pr_err("sst: message creation failed\n");
+               pr_err("message creation failed\n");
                return -ENOMEM;
        }
 
@@ -894,7 +896,7 @@ static int sst_prepare_input_buffers_rar(struct stream_info *str_info,
                                dbufs->ibufs->buff_entry[i].buffer,
                                sizeof(__u32));
                if (retval) {
-                       pr_err("sst:cpy from user fail\n");
+                       pr_err("cpy from user fail\n");
                        return -EAGAIN;
                }
                rar_buffers.info.type = dbufs->ibufs->type;
@@ -931,7 +933,7 @@ static int sst_prepare_input_buffers(struct stream_info *str_info,
 {
        int i, cpy_size, retval = 0;
 
-       pr_debug("sst:input_index = %d, input entries = %d\n",
+       pr_debug("input_index = %d, input entries = %d\n",
                         *input_index, dbufs->ibufs->entries);
        for (i = *input_index; i < dbufs->ibufs->entries; i++) {
 #ifdef CONFIG_MRST_RAR_HANDLER
@@ -939,7 +941,7 @@ static int sst_prepare_input_buffers(struct stream_info *str_info,
                        dbufs, input_index, in_copied,
                                input_index_valid_size, new_entry_flag);
                if (retval) {
-                       pr_err("sst: In prepare input buffers for RAR\n");
+                       pr_err("In prepare input buffers for RAR\n");
                        return -EIO;
                }
 #endif
@@ -947,10 +949,10 @@ static int sst_prepare_input_buffers(struct stream_info *str_info,
                if (*input_index_valid_size == 0)
                        *input_index_valid_size =
                                dbufs->ibufs->buff_entry[i].size;
-               pr_debug("sst:inout addr = %p, size = %d\n",
+               pr_debug("inout addr = %p, size = %d\n",
                        dbufs->ibufs->buff_entry[i].buffer,
                        *input_index_valid_size);
-               pr_debug("sst:decode_isize = %d, in_copied %d\n",
+               pr_debug("decode_isize = %d, in_copied %d\n",
                        str_info->decode_isize, *in_copied);
                if (*input_index_valid_size <=
                                        (str_info->decode_isize - *in_copied))
@@ -958,12 +960,12 @@ static int sst_prepare_input_buffers(struct stream_info *str_info,
                else
                        cpy_size = str_info->decode_isize - *in_copied;
 
-               pr_debug("sst:cpy size = %d\n", cpy_size);
+               pr_debug("cpy size = %d\n", cpy_size);
                if (!dbufs->ibufs->buff_entry[i].buffer) {
-                       pr_err("sst: i/p buffer is null\n");
+                       pr_err("i/p buffer is null\n");
                        return -EINVAL;
                }
-               pr_debug("sst:Try copy To %p, From %p, size %d\n",
+               pr_debug("Try copy To %p, From %p, size %d\n",
                                str_info->decode_ibuf + *in_copied,
                                dbufs->ibufs->buff_entry[i].buffer, cpy_size);
 
@@ -972,22 +974,22 @@ static int sst_prepare_input_buffers(struct stream_info *str_info,
                                (void *) dbufs->ibufs->buff_entry[i].buffer,
                                cpy_size);
                if (retval) {
-                       pr_err("sst: copy from user failed\n");
+                       pr_err("copy from user failed\n");
                        return -EIO;
                }
                *in_copied += cpy_size;
                *input_index_valid_size -= cpy_size;
-               pr_debug("sst:in buff size = %d, in_copied = %d\n",
+               pr_debug("in buff size = %d, in_copied = %d\n",
                        *input_index_valid_size, *in_copied);
                if (*input_index_valid_size != 0) {
-                       pr_debug("sst:more input buffers left\n");
+                       pr_debug("more input buffers left\n");
                        dbufs->ibufs->buff_entry[i].buffer += cpy_size;
                        break;
                }
                if (*in_copied == str_info->decode_isize &&
                        *input_index_valid_size == 0 &&
                        (i+1) <= dbufs->ibufs->entries) {
-                       pr_debug("sst:all input buffers copied\n");
+                       pr_debug("all input buffers copied\n");
                        *new_entry_flag = true;
                        *input_index = i + 1;
                        break;
@@ -1005,23 +1007,23 @@ static int sst_prepare_output_buffers(struct stream_info *str_info,
 
 {
        int i, cpy_size, retval = 0;
-       pr_debug("sst:output_index = %d, output entries = %d\n",
+       pr_debug("output_index = %d, output entries = %d\n",
                                *output_index,
                                dbufs->obufs->entries);
        for (i = *output_index; i < dbufs->obufs->entries; i++) {
                *output_index = i;
-               pr_debug("sst:output addr = %p, size = %d\n",
+               pr_debug("output addr = %p, size = %d\n",
                        dbufs->obufs->buff_entry[i].buffer,
                        dbufs->obufs->buff_entry[i].size);
-               pr_debug("sst:output_size = %d, out_copied = %d\n",
+               pr_debug("output_size = %d, out_copied = %d\n",
                                output_size, *out_copied);
                if (dbufs->obufs->buff_entry[i].size <
                                (output_size - *out_copied))
                        cpy_size = dbufs->obufs->buff_entry[i].size;
                else
                        cpy_size = output_size - *out_copied;
-               pr_debug("sst:cpy size = %d\n", cpy_size);
-               pr_debug("sst:Try copy To: %p, From %p, size %d\n",
+               pr_debug("cpy size = %d\n", cpy_size);
+               pr_debug("Try copy To: %p, From %p, size %d\n",
                                dbufs->obufs->buff_entry[i].buffer,
                                sst_drv_ctx->mmap_mem + *out_copied,
                                cpy_size);
@@ -1029,13 +1031,13 @@ static int sst_prepare_output_buffers(struct stream_info *str_info,
                                        sst_drv_ctx->mmap_mem + *out_copied,
                                        cpy_size);
                if (retval) {
-                       pr_err("sst: copy to user failed\n");
+                       pr_err("copy to user failed\n");
                        return -EIO;
                } else
-                       pr_debug("sst:copy to user passed\n");
+                       pr_debug("copy to user passed\n");
                *out_copied += cpy_size;
                dbufs->obufs->buff_entry[i].size -= cpy_size;
-               pr_debug("sst:o/p buff size %d, out_copied %d\n",
+               pr_debug("o/p buff size %d, out_copied %d\n",
                        dbufs->obufs->buff_entry[i].size, *out_copied);
                if (dbufs->obufs->buff_entry[i].size != 0) {
                        *output_index = i;
@@ -1073,7 +1075,7 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
        unsigned long long input_bytes, output_bytes;
 
        sst_drv_ctx->scard_ops->power_down_pmic();
-       pr_debug("sst: Powering_down_PMIC...\n");
+       pr_debug("Powering_down_PMIC...\n");
 
        retval = sst_validate_strid(str_id);
        if (retval)
@@ -1081,7 +1083,7 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
 
        str_info = &sst_drv_ctx->streams[str_id];
        if (str_info->status != STREAM_INIT) {
-               pr_err("sst: invalid stream state = %d\n",
+               pr_err("invalid stream state = %d\n",
                               str_info->status);
                return -EINVAL;
        }
@@ -1098,7 +1100,7 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
        retval =  sst_allocate_decode_buf(str_info, dbufs,
                                cum_input_given, cum_output_given);
        if (retval) {
-               pr_err("sst: mem allocation failed, abort!!!\n");
+               pr_err("mem allocation failed, abort!!!\n");
                retval = -ENOMEM;
                goto finish;
        }
@@ -1114,7 +1116,7 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
                        dbufs, &input_index, &in_copied,
                        &input_index_valid_size, &new_entry_flag);
                if (retval) {
-                       pr_err("sst: prepare in buffers failed\n");
+                       pr_err("prepare in buffers failed\n");
                        goto finish;
                }
 
@@ -1145,8 +1147,8 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
                                str_info->decode_osize = dbufs->obufs->
                                        buff_entry[output_index].size;
                                str_info->decode_obuf_type = dbufs->obufs->type;
-                               pr_debug("sst:DRM handling\n");
-                               pr_debug("o/p_add=0x%lu Size=0x%x",
+                               pr_debug("DRM handling\n");
+                               pr_debug("o/p_add=0x%lu Size=0x%x\n",
                                        (unsigned long) str_info->decode_obuf,
                                        str_info->decode_osize);
                        } else {
@@ -1160,7 +1162,7 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
                if (str_info->ops != STREAM_OPS_PLAYBACK_DRM) {
                        if (str_info->decode_isize > in_copied) {
                                str_info->decode_isize = in_copied;
-                               pr_debug("sst:i/p size = %d\n",
+                               pr_debug("i/p size = %d\n",
                                                str_info->decode_isize);
                        }
                }
@@ -1168,20 +1170,19 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
 
                retval = sst_send_decode_mess(str_id, str_info, &dec_info);
                if (retval || dec_info.input_bytes_consumed == 0) {
-                       pr_err(
-                               "SST ERR: mess failed or no input consumed\n");
+                       pr_err("SST ERR: mess failed or no input consumed\n");
                        goto finish;
                }
                input_bytes = dec_info.input_bytes_consumed;
                output_bytes = dec_info.output_bytes_produced;
 
-               pr_debug("sst:in_copied=%d, con=%lld, prod=%lld\n",
+               pr_debug("in_copied=%d, con=%lld, prod=%lld\n",
                        in_copied, input_bytes, output_bytes);
                if (dbufs->obufs->type == SST_BUF_RAR) {
                        output_index += 1;
                        if (output_index == dbufs->obufs->entries) {
                                copy_in_done = true;
-                               pr_debug("sst:all i/p cpy done\n");
+                               pr_debug("all i/p cpy done\n");
                        }
                        total_output += output_bytes;
                } else {
@@ -1190,14 +1191,14 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
                        retval = sst_prepare_output_buffers(str_info, dbufs,
                                &output_index, output_size, &out_copied);
                        if (retval) {
-                               pr_err("sst:prep out buff fail\n");
+                               pr_err("prep out buff fail\n");
                                goto finish;
                        }
                        if (str_info->ops != STREAM_OPS_PLAYBACK_DRM) {
                                if (in_copied != input_bytes) {
                                        int bytes_left = in_copied -
                                                                input_bytes;
-                                       pr_debug("sst:bytes %d\n",
+                                       pr_debug("bytes %d\n",
                                                        bytes_left);
                                        if (new_entry_flag == true)
                                                input_index--;
@@ -1237,7 +1238,7 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
                        total_output += out_copied;
                        if (str_info->decode_osize != out_copied) {
                                str_info->decode_osize -= out_copied;
-                               pr_debug("sst:output size modified = %d\n",
+                               pr_debug("output size modified = %d\n",
                                                str_info->decode_osize);
                        }
                }
@@ -1251,16 +1252,16 @@ int sst_decode(int str_id, struct snd_sst_dbufs *dbufs)
                } else {
                        if (total_output == cum_output_given) {
                                copy_out_done = true;
-                               pr_debug("sst:all o/p cpy done\n");
+                               pr_debug("all o/p cpy done\n");
                        }
 
                        if (total_input == cum_input_given) {
                                copy_in_done = true;
-                               pr_debug("sst:all i/p cpy done\n");
+                               pr_debug("all i/p cpy done\n");
                        }
                }
 
-               pr_debug("sst:copy_out = %d, copy_in = %d\n",
+               pr_debug("copy_out = %d, copy_in = %d\n",
                                copy_out_done, copy_in_done);
        }
 
index 4c0264ceaa889459f5b84371c25052c167bf1ccb..47b91e500c3c61909c2f1e82a93eac2521304322 100644 (file)
@@ -24,6 +24,9 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  * ALSA driver for Intel MID sound card chipset
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/slab.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
@@ -118,7 +121,7 @@ static int snd_intelmad_pcm_trigger(struct snd_pcm_substream *substream,
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               pr_debug("sst: Trigger Start\n");
+               pr_debug("Trigger Start\n");
                ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_START,
                                &stream->stream_info.str_id);
                if (ret_val)
@@ -128,7 +131,7 @@ static int snd_intelmad_pcm_trigger(struct snd_pcm_substream *substream,
                stream->stream_status = RUNNING;
                break;
        case SNDRV_PCM_TRIGGER_STOP:
-               pr_debug("sst: in stop\n");
+               pr_debug("in stop\n");
                ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_DROP,
                                &stream->stream_info.str_id);
                if (ret_val)
@@ -136,7 +139,7 @@ static int snd_intelmad_pcm_trigger(struct snd_pcm_substream *substream,
                stream->stream_status = DROPPED;
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               pr_debug("sst: in pause\n");
+               pr_debug("in pause\n");
                ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_PAUSE,
                                &stream->stream_info.str_id);
                if (ret_val)
@@ -144,7 +147,7 @@ static int snd_intelmad_pcm_trigger(struct snd_pcm_substream *substream,
                stream->stream_status = PAUSED;
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               pr_debug("sst: in pause release\n");
+               pr_debug("in pause release\n");
                ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_RESUME,
                                                &stream->stream_info.str_id);
                if (ret_val)
@@ -170,17 +173,17 @@ static int snd_intelmad_pcm_prepare(struct snd_pcm_substream *substream)
        int ret_val = 0;
        struct snd_intelmad *intelmaddata;
 
-       pr_debug("sst: pcm_prepare called\n");
+       pr_debug("pcm_prepare called\n");
 
        WARN_ON(!substream);
        stream = substream->runtime->private_data;
        intelmaddata = snd_pcm_substream_chip(substream);
-       pr_debug("sst: pb cnt = %d cap cnt = %d\n",\
+       pr_debug("pb cnt = %d cap cnt = %d\n",\
                intelmaddata->playback_cnt,
                intelmaddata->capture_cnt);
 
        if (stream->stream_info.str_id) {
-               pr_debug("sst: Prepare called for already set stream\n");
+               pr_debug("Prepare called for already set stream\n");
                ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_DROP,
                                        &stream->stream_info.str_id);
                return ret_val;
@@ -197,7 +200,7 @@ static int snd_intelmad_pcm_prepare(struct snd_pcm_substream *substream)
        /* return back the stream id */
        snprintf(substream->pcm->id, sizeof(substream->pcm->id),
                        "%d", stream->stream_info.str_id);
-       pr_debug("sst: stream id to user = %s\n",
+       pr_debug("stream id to user = %s\n",
                        substream->pcm->id);
 
        ret_val = snd_intelmad_init_stream(substream);
@@ -212,7 +215,7 @@ static int snd_intelmad_hw_params(struct snd_pcm_substream *substream,
 {
        int ret_val;
 
-       pr_debug("sst: snd_intelmad_hw_params called\n");
+       pr_debug("snd_intelmad_hw_params called\n");
        ret_val = snd_pcm_lib_malloc_pages(substream,
                        params_buffer_bytes(hw_params));
        memset(substream->runtime->dma_area, 0,
@@ -223,7 +226,7 @@ static int snd_intelmad_hw_params(struct snd_pcm_substream *substream,
 
 static int snd_intelmad_hw_free(struct snd_pcm_substream *substream)
 {
-       pr_debug("sst: snd_intelmad_hw_free called\n");
+       pr_debug("snd_intelmad_hw_free called\n");
        return snd_pcm_lib_free_pages(substream);
 }
 
@@ -253,12 +256,12 @@ static snd_pcm_uframes_t snd_intelmad_pcm_pointer
        ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_BUFFER_POINTER,
                                &stream->stream_info);
        if (ret_val) {
-               pr_err("sst: error code = 0x%x\n", ret_val);
+               pr_err("error code = 0x%x\n", ret_val);
                return ret_val;
        }
-       pr_debug("sst: samples reported out 0x%llx\n",
+       pr_debug("samples reported out 0x%llx\n",
                        stream->stream_info.buffer_ptr);
-       pr_debug("sst: Frame bits:: %d period_count :: %d\n",
+       pr_debug("Frame bits:: %d period_count :: %d\n",
                        (int)substream->runtime->frame_bits,
                        (int)substream->runtime->period_size);
 
@@ -283,10 +286,10 @@ static int snd_intelmad_close(struct snd_pcm_substream *substream)
 
        stream = substream->runtime->private_data;
 
-       pr_debug("sst: snd_intelmad_close called\n");
+       pr_debug("snd_intelmad_close called\n");
        intelmaddata = snd_pcm_substream_chip(substream);
 
-       pr_debug("sst: str id = %d\n", stream->stream_info.str_id);
+       pr_debug("str id = %d\n", stream->stream_info.str_id);
        if (stream->stream_info.str_id) {
                /* SST API to actually stop/free the stream */
                ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_FREE,
@@ -296,7 +299,7 @@ static int snd_intelmad_close(struct snd_pcm_substream *substream)
                else
                        intelmaddata->capture_cnt--;
        }
-       pr_debug("sst: snd_intelmad_close : pb cnt = %d cap cnt = %d\n",
+       pr_debug("snd_intelmad_close : pb cnt = %d cap cnt = %d\n",
                intelmaddata->playback_cnt, intelmaddata->capture_cnt);
        kfree(substream->runtime->private_data);
        return ret_val;
@@ -319,7 +322,7 @@ static int snd_intelmad_open(struct snd_pcm_substream *substream,
 
        WARN_ON(!substream);
 
-       pr_debug("sst: snd_intelmad_open called\n");
+       pr_debug("snd_intelmad_open called\n");
 
        intelmaddata = snd_pcm_substream_chip(substream);
        runtime = substream->runtime;
@@ -456,17 +459,17 @@ void sst_mad_send_jack_report(struct snd_jack *jack,
 {
 
        if (!jack) {
-               pr_debug("sst: MAD error jack empty\n");
+               pr_debug("MAD error jack empty\n");
 
        } else {
-               pr_debug("sst: MAD send jack report for = %d!!!\n", status);
-               pr_debug("sst: MAD send jack report %d\n", jack->type);
+               pr_debug("MAD send jack report for = %d!!!\n", status);
+               pr_debug("MAD send jack report %d\n", jack->type);
                snd_jack_report(jack, status);
 
                /*button pressed and released */
                if (buttonpressevent)
                        snd_jack_report(jack, 0);
-               pr_debug("sst: MAD sending jack report Done !!!\n");
+               pr_debug("MAD sending jack report Done !!!\n");
        }
 
 
@@ -490,7 +493,7 @@ void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata)
        if (intsts & 0x4) {
 
                if (!(intelmid_audio_interrupt_enable)) {
-                       pr_debug("sst: Audio interrupt enable\n");
+                       pr_debug("Audio interrupt enable\n");
                        sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3);
 
                        sst_sc_reg_access(sc_access_write, PMIC_WRITE, 1);
@@ -500,7 +503,7 @@ void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata)
 
                }
                /* send headphone detect */
-               pr_debug("sst: MAD headphone %d\n", intsts & 0x4);
+               pr_debug("MAD headphone %d\n", intsts & 0x4);
                jack = &intelmaddata->jack[0].jack;
                present = !(intelmaddata->jack[0].jack_status);
                intelmaddata->jack[0].jack_status = present;
@@ -510,7 +513,7 @@ void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata)
 
        if (intsts & 0x2) {
                /* send short push */
-               pr_debug("sst: MAD short push %d\n", intsts & 0x2);
+               pr_debug("MAD short push %d\n", intsts & 0x2);
                jack = &intelmaddata->jack[2].jack;
                present = 1;
                jack_event_flag = 1;
@@ -518,7 +521,7 @@ void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata)
        }
        if (intsts & 0x1) {
                /* send long push */
-               pr_debug("sst: MAD long push %d\n", intsts & 0x1);
+               pr_debug("MAD long push %d\n", intsts & 0x1);
                jack = &intelmaddata->jack[3].jack;
                present = 1;
                jack_event_flag = 1;
@@ -526,7 +529,7 @@ void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata)
        }
        if (intsts & 0x8) {
                if (!(intelmid_audio_interrupt_enable)) {
-                       pr_debug("sst: Audio interrupt enable\n");
+                       pr_debug("Audio interrupt enable\n");
                        sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 3);
 
                        sst_sc_reg_access(sc_access_write, PMIC_WRITE, 1);
@@ -535,7 +538,7 @@ void sst_mad_jackdetection_fs(u8 intsts , struct snd_intelmad *intelmaddata)
                        intelmaddata->jack[1].jack_status = 0;
                }
                /* send headset detect */
-               pr_debug("sst: MAD headset = %d\n", intsts & 0x8);
+               pr_debug("MAD headset = %d\n", intsts & 0x8);
                jack = &intelmaddata->jack[1].jack;
                present = !(intelmaddata->jack[1].jack_status);
                intelmaddata->jack[1].jack_status = present;
@@ -558,10 +561,10 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata)
 
        scard_ops = intelmaddata->sstdrv_ops->scard_ops;
 
-       pr_debug("sst: previous value: %x\n", intelmaddata->jack_prev_state);
+       pr_debug("previous value: %x\n", intelmaddata->jack_prev_state);
 
        if (!(intelmid_audio_interrupt_enable)) {
-               pr_debug("sst: Audio interrupt enable\n");
+               pr_debug("Audio interrupt enable\n");
                intelmaddata->jack_prev_state = 0xC0;
                intelmid_audio_interrupt_enable = 1;
        }
@@ -572,12 +575,12 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata)
                        sc_access_read.reg_addr = 0x201;
                        sst_sc_reg_access(&sc_access_read, PMIC_READ, 1);
                        value = (sc_access_read.value);
-                       pr_debug("sst: value returned = 0x%x\n", value);
+                       pr_debug("value returned = 0x%x\n", value);
                }
 
                if (jack_prev_state == 0xc0 && value == 0x40) {
                        /*headset detected. */
-                       pr_debug("sst: MAD headset inserted\n");
+                       pr_debug("MAD headset inserted\n");
                        jack = &intelmaddata->jack[1].jack;
                        present = 1;
                        jack_event_flag = 1;
@@ -587,7 +590,7 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata)
 
                if (jack_prev_state == 0xc0 && value == 0x00) {
                        /* headphone  detected. */
-                       pr_debug("sst: MAD headphone inserted\n");
+                       pr_debug("MAD headphone inserted\n");
                        jack = &intelmaddata->jack[0].jack;
                        present = 1;
                        jack_event_flag = 1;
@@ -596,9 +599,9 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata)
 
                if (jack_prev_state == 0x40 && value == 0xc0) {
                        /*headset  removed*/
-                       pr_debug("sst: Jack headset status %d\n",
+                       pr_debug("Jack headset status %d\n",
                                intelmaddata->jack[1].jack_status);
-                       pr_debug("sst: MAD headset removed\n");
+                       pr_debug("MAD headset removed\n");
                        jack = &intelmaddata->jack[1].jack;
                        present = 0;
                        jack_event_flag = 1;
@@ -607,9 +610,9 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata)
 
                if (jack_prev_state == 0x00 && value == 0xc0) {
                        /* headphone  detected. */
-                       pr_debug("sst: Jack headphone status %d\n",
+                       pr_debug("Jack headphone status %d\n",
                                        intelmaddata->jack[0].jack_status);
-                       pr_debug("sst: headphone removed\n");
+                       pr_debug("headphone removed\n");
                        jack = &intelmaddata->jack[0].jack;
                        present = 0;
                        jack_event_flag = 1;
@@ -618,7 +621,7 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata)
                if (jack_prev_state == 0x40 && value == 0x00) {
                        /*button pressed*/
                        do_gettimeofday(&intelmaddata->jack[1].buttonpressed);
-                       pr_debug("sst: MAD button press detected n");
+                       pr_debug("MAD button press detected\n");
                }
 
 
@@ -628,19 +631,19 @@ void sst_mad_jackdetection_mx(u8 intsts, struct snd_intelmad *intelmaddata)
                                do_gettimeofday(
                                        &intelmaddata->jack[1].buttonreleased);
                                /*button pressed */
-                               pr_debug("sst: Button Released detected\n");
+                               pr_debug("Button Released detected\n");
                                timediff = intelmaddata->jack[1].
                                        buttonreleased.tv_sec - intelmaddata->
                                        jack[1].buttonpressed.tv_sec;
                                buttonpressflag = 1;
                                if (timediff > 1) {
-                                       pr_debug("sst: long press detected\n");
+                                       pr_debug("long press detected\n");
                                        /* send headphone detect/undetect */
                                        jack = &intelmaddata->jack[3].jack;
                                        present = 1;
                                        jack_event_flag = 1;
                                } else {
-                                       pr_debug("sst: short press detected\n");
+                                       pr_debug("short press detected\n");
                                        /* send headphone detect/undetect */
                                        jack = &intelmaddata->jack[2].jack;
                                        present = 1;
@@ -667,24 +670,24 @@ void sst_mad_jackdetection_nec(u8 intsts, struct snd_intelmad *intelmaddata)
                sc_access_read.reg_addr = 0x132;
                sst_sc_reg_access(&sc_access_read, PMIC_READ, 1);
                value = (sc_access_read.value);
-               pr_debug("sst: value returned = 0x%x\n", value);
+               pr_debug("value returned = 0x%x\n", value);
        }
        if (intsts & 0x1) {
-               pr_debug("sst: headset detected\n");
+               pr_debug("headset detected\n");
                /* send headset detect/undetect */
                jack = &intelmaddata->jack[1].jack;
                present = (value == 0x1) ? 1 : 0;
                jack_event_flag = 1;
        }
        if (intsts & 0x2) {
-               pr_debug("sst: headphone detected\n");
+               pr_debug("headphone detected\n");
                /* send headphone detect/undetect */
                jack = &intelmaddata->jack[0].jack;
                present = (value == 0x2) ? 1 : 0;
                jack_event_flag = 1;
        }
        if (intsts & 0x4) {
-               pr_debug("sst: short push detected\n");
+               pr_debug("short push detected\n");
                /* send short push */
                jack = &intelmaddata->jack[2].jack;
                present = 1;
@@ -692,7 +695,7 @@ void sst_mad_jackdetection_nec(u8 intsts, struct snd_intelmad *intelmaddata)
                buttonpressflag = 1;
        }
        if (intsts & 0x8) {
-               pr_debug("sst: long push detected\n");
+               pr_debug("long push detected\n");
                /* send long push */
                jack = &intelmaddata->jack[3].jack;
                present = 1;
@@ -738,12 +741,12 @@ static int __devinit snd_intelmad_register_irq(
        u32 regbase = AUDINT_BASE, regsize = 8;
        char *drv_name;
 
-       pr_debug("sst: irq reg done, regbase 0x%x, regsize 0x%x\n",
+       pr_debug("irq reg done, regbase 0x%x, regsize 0x%x\n",
                                        regbase, regsize);
        intelmaddata->int_base = ioremap_nocache(regbase, regsize);
        if (!intelmaddata->int_base)
-               pr_err("sst: Mapping of cache failed\n");
-       pr_debug("sst: irq = 0x%x\n", intelmaddata->irq);
+               pr_err("Mapping of cache failed\n");
+       pr_debug("irq = 0x%x\n", intelmaddata->irq);
        if (intelmaddata->cpu_id == CPU_CHIP_PENWELL)
                drv_name = DRIVER_NAME_MFLD;
        else
@@ -753,7 +756,7 @@ static int __devinit snd_intelmad_register_irq(
                                IRQF_SHARED, drv_name,
                                intelmaddata);
        if (ret_val)
-               pr_err("sst: cannot register IRQ\n");
+               pr_err("cannot register IRQ\n");
        return ret_val;
 }
 
@@ -775,10 +778,10 @@ static int __devinit snd_intelmad_sst_register(
                if (ret_val)
                        return ret_val;
                sst_card_vendor_id = (vendor_addr.value & (MASK2|MASK1|MASK0));
-               pr_debug("sst: orginal n extrated vendor id = 0x%x %d\n",
+               pr_debug("orginal n extrated vendor id = 0x%x %d\n",
                                vendor_addr.value, sst_card_vendor_id);
                if (sst_card_vendor_id < 0 || sst_card_vendor_id > 2) {
-                       pr_err("sst: vendor card not supported!!\n");
+                       pr_err("vendor card not supported!!\n");
                        return -EIO;
                }
        } else
@@ -801,7 +804,7 @@ static int __devinit snd_intelmad_sst_register(
        /* registering with SST driver to get access to SST APIs to use */
        ret_val = register_sst_card(intelmaddata->sstdrv_ops);
        if (ret_val) {
-               pr_err("sst: sst card registration failed\n");
+               pr_err("sst card registration failed\n");
                return ret_val;
        }
 
@@ -832,7 +835,7 @@ static int __devinit snd_intelmad_pcm_new(struct snd_card *card,
        char name[32] = INTEL_MAD;
        struct snd_pcm_ops *pb_ops = NULL, *cap_ops = NULL;
 
-       pr_debug("sst: called for pb %d, cp %d, idx %d\n", pb, cap, index);
+       pr_debug("called for pb %d, cp %d, idx %d\n", pb, cap, index);
        ret_val = snd_pcm_new(card, name, index, pb, cap, &pcm);
        if (ret_val)
                return ret_val;
@@ -878,7 +881,7 @@ static int __devinit snd_intelmad_pcm(struct snd_card *card,
 
        WARN_ON(!card);
        WARN_ON(!intelmaddata);
-       pr_debug("sst: snd_intelmad_pcm called\n");
+       pr_debug("snd_intelmad_pcm called\n");
        ret_val = snd_intelmad_pcm_new(card, intelmaddata, 1, 1, 0);
        if (intelmaddata->cpu_id == CPU_CHIP_LINCROFT)
                return ret_val;
@@ -903,7 +906,7 @@ static int snd_intelmad_jack(struct snd_intelmad *intelmaddata)
        struct snd_jack *jack;
        int retval;
 
-       pr_debug("sst: snd_intelmad_jack called\n");
+       pr_debug("snd_intelmad_jack called\n");
        jack = &intelmaddata->jack[0].jack;
        retval = snd_jack_new(intelmaddata->card, "Headphone",
                                SND_JACK_HEADPHONE, &jack);
@@ -982,9 +985,9 @@ static int __devinit snd_intelmad_mixer(struct snd_intelmad *intelmaddata)
                ret_val = snd_ctl_add(card,
                                snd_ctl_new1(&controls[idx],
                                intelmaddata));
-               pr_debug("sst: mixer[idx]=%d added\n", idx);
+               pr_debug("mixer[idx]=%d added\n", idx);
                if (ret_val) {
-                       pr_err("sst: in adding of control index = %d\n", idx);
+                       pr_err("in adding of control index = %d\n", idx);
                        break;
                }
        }
@@ -999,7 +1002,7 @@ static int snd_intelmad_dev_free(struct snd_device *device)
 
        intelmaddata = device->device_data;
 
-       pr_debug("sst: snd_intelmad_dev_free called\n");
+       pr_debug("snd_intelmad_dev_free called\n");
        snd_card_free(intelmaddata->card);
        /*genl_unregister_family(&audio_event_genl_family);*/
        unregister_sst_card(intelmaddata->sstdrv_ops);
@@ -1040,23 +1043,23 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev)
        const struct platform_device_id *id = platform_get_device_id(pdev);
        unsigned int cpu_id = (unsigned int)id->driver_data;
 
-       pr_debug("sst: probe for %s cpu_id %d\n", pdev->name, cpu_id);
+       pr_debug("probe for %s cpu_id %d\n", pdev->name, cpu_id);
        if (!strcmp(pdev->name, DRIVER_NAME_MRST))
-               pr_debug("sst: detected MRST\n");
+               pr_debug("detected MRST\n");
        else if (!strcmp(pdev->name, DRIVER_NAME_MFLD))
-               pr_debug("sst: detected MFLD\n");
+               pr_debug("detected MFLD\n");
        else {
-               pr_err("sst: detected unknown device abort!!\n");
+               pr_err("detected unknown device abort!!\n");
                return -EIO;
        }
        if ((cpu_id < CPU_CHIP_LINCROFT) || (cpu_id > CPU_CHIP_PENWELL)) {
-               pr_err("sst: detected unknown cpu_id abort!!\n");
+               pr_err("detected unknown cpu_id abort!!\n");
                return -EIO;
        }
        /* allocate memory for saving internal context and working */
        intelmaddata = kzalloc(sizeof(*intelmaddata), GFP_KERNEL);
        if (!intelmaddata) {
-               pr_debug("sst: mem alloctn fail\n");
+               pr_debug("mem alloctn fail\n");
                return -ENOMEM;
        }
 
@@ -1064,7 +1067,7 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev)
        intelmaddata->sstdrv_ops = kzalloc(sizeof(struct intel_sst_card_ops),
                                        GFP_KERNEL);
        if (!intelmaddata->sstdrv_ops) {
-               pr_err("sst: mem allocation for ops fail\n");
+               pr_err("mem allocation for ops fail\n");
                kfree(intelmaddata);
                return -ENOMEM;
        }
@@ -1073,7 +1076,7 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev)
        /* create a card instance with ALSA framework */
        ret_val = snd_card_create(card_index, card_id, THIS_MODULE, 0, &card);
        if (ret_val) {
-               pr_err("sst: snd_card_create fail\n");
+               pr_err("snd_card_create fail\n");
                goto free_allocs;
        }
 
@@ -1092,7 +1095,7 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev)
        /* registering with LPE driver to get access to SST APIs to use */
        ret_val = snd_intelmad_sst_register(intelmaddata);
        if (ret_val) {
-               pr_err("sst: snd_intelmad_sst_register failed\n");
+               pr_err("snd_intelmad_sst_register failed\n");
                goto free_allocs;
        }
 
@@ -1100,19 +1103,19 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev)
 
        ret_val = snd_intelmad_pcm(card, intelmaddata);
        if (ret_val) {
-               pr_err("sst: snd_intelmad_pcm failed\n");
+               pr_err("snd_intelmad_pcm failed\n");
                goto free_allocs;
        }
 
        ret_val = snd_intelmad_mixer(intelmaddata);
        if (ret_val) {
-               pr_err("sst: snd_intelmad_mixer failed\n");
+               pr_err("snd_intelmad_mixer failed\n");
                goto free_allocs;
        }
 
        ret_val = snd_intelmad_jack(intelmaddata);
        if (ret_val) {
-               pr_err("sst: snd_intelmad_jack failed\n");
+               pr_err("snd_intelmad_jack failed\n");
                goto free_allocs;
        }
 
@@ -1126,31 +1129,31 @@ int __devinit snd_intelmad_probe(struct platform_device *pdev)
 
        ret_val = snd_intelmad_register_irq(intelmaddata);
        if (ret_val) {
-               pr_err("sst: snd_intelmad_register_irq fail\n");
+               pr_err("snd_intelmad_register_irq fail\n");
                goto free_allocs;
        }
 
        /* internal function call to register device with ALSA */
        ret_val = snd_intelmad_create(intelmaddata, card);
        if (ret_val) {
-               pr_err("sst: snd_intelmad_create failed\n");
+               pr_err("snd_intelmad_create failed\n");
                goto free_allocs;
        }
        card->private_data = &intelmaddata;
        snd_card_set_dev(card, &pdev->dev);
        ret_val = snd_card_register(card);
        if (ret_val) {
-               pr_err("sst: snd_card_register failed\n");
+               pr_err("snd_card_register failed\n");
                goto free_allocs;
        }
 
-       pr_debug("sst:snd_intelmad_probe complete\n");
+       pr_debug("snd_intelmad_probe complete\n");
        return ret_val;
 
 free_mad_jack_wq:
        destroy_workqueue(intelmaddata->mad_jack_wq);
 free_allocs:
-       pr_err("sst: probe failed\n");
+       pr_err("probe failed\n");
        snd_card_free(card);
        kfree(intelmaddata->sstdrv_ops);
        kfree(intelmaddata);
@@ -1200,7 +1203,7 @@ static struct platform_driver snd_intelmad_driver = {
  */
 static int __init alsa_card_intelmad_init(void)
 {
-       pr_debug("sst: mad_init called\n");
+       pr_debug("mad_init called\n");
        return platform_driver_register(&snd_intelmad_driver);
 }
 
@@ -1211,7 +1214,7 @@ static int __init alsa_card_intelmad_init(void)
  */
 static void __exit alsa_card_intelmad_exit(void)
 {
-       pr_debug("sst:mad_exit called\n");
+       pr_debug("mad_exit called\n");
        return platform_driver_unregister(&snd_intelmad_driver);
 }
 
index 03b4ece02f913278d8b3506374482c059a0c6b1f..0d9135715c74f0c9baf61d914d4a665e8f937986 100644 (file)
@@ -24,6 +24,9 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *  ALSA driver handling mixer controls for Intel MAD chipset
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <sound/core.h>
 #include <sound/control.h>
 #include "jack.h"
@@ -216,7 +219,7 @@ static int snd_intelmad_volume_get(struct snd_kcontrol *kcontrol,
        struct snd_intelmad *intelmaddata;
        struct snd_pmic_ops *scard_ops;
 
-       pr_debug("sst: snd_intelmad_volume_get called\n");
+       pr_debug("snd_intelmad_volume_get called\n");
 
        WARN_ON(!uval);
        WARN_ON(!kcontrol);
@@ -273,7 +276,7 @@ static int snd_intelmad_mute_get(struct snd_kcontrol *kcontrol,
        struct snd_intelmad *intelmaddata;
        struct snd_pmic_ops *scard_ops;
 
-       pr_debug("sst: Mute_get called\n");
+       pr_debug("Mute_get called\n");
 
        WARN_ON(!uval);
        WARN_ON(!kcontrol);
@@ -332,7 +335,7 @@ static int snd_intelmad_volume_set(struct snd_kcontrol *kcontrol,
        struct snd_intelmad *intelmaddata;
        struct snd_pmic_ops *scard_ops;
 
-       pr_debug("sst: volume set called:%ld %ld\n",
+       pr_debug("volume set called:%ld %ld\n",
                        uval->value.integer.value[0],
                        uval->value.integer.value[1]);
 
@@ -387,7 +390,7 @@ static int snd_intelmad_mute_set(struct snd_kcontrol *kcontrol,
        struct snd_intelmad *intelmaddata;
        struct snd_pmic_ops *scard_ops;
 
-       pr_debug("sst: snd_intelmad_mute_set called\n");
+       pr_debug("snd_intelmad_mute_set called\n");
 
        WARN_ON(!uval);
        WARN_ON(!kcontrol);
@@ -455,7 +458,7 @@ static int snd_intelmad_device_get(struct snd_kcontrol *kcontrol,
 {
        struct snd_intelmad *intelmaddata;
        struct snd_pmic_ops *scard_ops;
-       pr_debug("sst: device_get called\n");
+       pr_debug("device_get called\n");
 
        WARN_ON(!uval);
        WARN_ON(!kcontrol);
@@ -492,7 +495,7 @@ static int snd_intelmad_device_set(struct snd_kcontrol *kcontrol,
        struct snd_pmic_ops *scard_ops;
        int ret_val = 0, vendor, status;
 
-       pr_debug("sst: snd_intelmad_device_set called\n");
+       pr_debug("snd_intelmad_device_set called\n");
 
        WARN_ON(!uval);
        WARN_ON(!kcontrol);
index 4d1755efceef242e3e9dda9a613bd37abcb1c00d..da093ed0cd88c540305fc376d44ba8e6526921d8 100644 (file)
@@ -24,6 +24,8 @@
  * This file contains the control operations of msic vendors
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/pci.h>
 #include <linux/file.h>
 #include "intel_sst.h"
@@ -83,7 +85,7 @@ static int msic_init_card(void)
        snd_msic_ops.cap_on = 0;
        snd_msic_ops.input_dev_id = DMIC; /*def dev*/
        snd_msic_ops.output_dev_id = STEREO_HEADPHONE;
-       pr_debug("sst: msic init complete!!\n");
+       pr_debug("msic init complete!!\n");
        return 0;
 }
 
@@ -173,7 +175,7 @@ static int msic_power_up_pb(unsigned int device)
                        return retval;
        }
 
-       pr_debug("sst: powering up pb.... Device %d\n", device);
+       pr_debug("powering up pb.... Device %d\n", device);
        sst_sc_reg_access(sc_access1, PMIC_WRITE, 4);
        switch (device) {
        case SND_SST_DEVICE_HEADSET:
@@ -205,7 +207,7 @@ static int msic_power_up_pb(unsigned int device)
                break;
 
        default:
-               pr_warn("sst: Wrong Device %d, selected %d\n",
+               pr_warn("Wrong Device %d, selected %d\n",
                               device, snd_msic_ops.output_dev_id);
        }
        return sst_sc_reg_access(sc_access_pcm2, PMIC_READ_MODIFY, 1);
@@ -268,7 +270,7 @@ static int msic_power_up_cp(unsigned int device)
                        return retval;
        }
 
-       pr_debug("sst: powering up cp....%d\n", snd_msic_ops.input_dev_id);
+       pr_debug("powering up cp....%d\n", snd_msic_ops.input_dev_id);
        sst_sc_reg_access(sc_access2, PMIC_READ_MODIFY, 1);
        snd_msic_ops.cap_on = 1;
        if (snd_msic_ops.input_dev_id == AMIC)
@@ -283,7 +285,7 @@ static int msic_power_down(void)
 {
        int retval = 0;
 
-       pr_debug("sst: powering dn msic\n");
+       pr_debug("powering dn msic\n");
        snd_msic_ops.pb_on = 0;
        snd_msic_ops.cap_on = 0;
        return retval;
@@ -293,7 +295,7 @@ static int msic_power_down_pb(void)
 {
        int retval = 0;
 
-       pr_debug("sst: powering dn pb....\n");
+       pr_debug("powering dn pb....\n");
        snd_msic_ops.pb_on = 0;
        return retval;
 }
@@ -302,7 +304,7 @@ static int msic_power_down_cp(void)
 {
        int retval = 0;
 
-       pr_debug("sst: powering dn cp....\n");
+       pr_debug("powering dn cp....\n");
        snd_msic_ops.cap_on = 0;
        return retval;
 }
@@ -311,7 +313,7 @@ static int msic_set_selected_output_dev(u8 value)
 {
        int retval = 0;
 
-       pr_debug("sst: msic set selected output:%d\n", value);
+       pr_debug("msic set selected output:%d\n", value);
        snd_msic_ops.output_dev_id = value;
        if (snd_msic_ops.pb_on)
                msic_power_up_pb(SND_SST_DEVICE_HEADSET);
@@ -330,15 +332,15 @@ static int msic_set_selected_input_dev(u8 value)
        };
        int retval = 0;
 
-       pr_debug("sst: msic_set_selected_input_dev:%d\n", value);
+       pr_debug("msic_set_selected_input_dev:%d\n", value);
        snd_msic_ops.input_dev_id = value;
        switch (value) {
        case AMIC:
-               pr_debug("sst: Selecting AMIC1\n");
+               pr_debug("Selecting AMIC1\n");
                retval = sst_sc_reg_access(sc_access_amic, PMIC_WRITE, 1);
                break;
        case DMIC:
-               pr_debug("sst: Selecting DMIC1\n");
+               pr_debug("Selecting DMIC1\n");
                retval = sst_sc_reg_access(sc_access_dmic, PMIC_WRITE, 1);
                break;
        default:
index 9ed9475ccc7be3a709071428fb0ace76bfd7eb43..4f9bdf364dca79422ce5b40afad9f04d42734b58 100644 (file)
@@ -23,6 +23,9 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  * ALSA driver for Intel MID sound card chipset - holding private functions
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/io.h>
 #include <asm/intel_scu_ipc.h>
 #include <sound/core.h>
@@ -50,7 +53,7 @@ void period_elapsed(void *mad_substream)
 
        if (stream->stream_status != RUNNING)
                return;
-       pr_debug("sst: calling period elapsed\n");
+       pr_debug("calling period elapsed\n");
        snd_pcm_period_elapsed(substream);
        return;
 }
@@ -76,8 +79,8 @@ int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream)
        param.uc.pcm_params.period_count = substream->runtime->period_size;
        param.uc.pcm_params.ring_buffer_addr =
                                virt_to_phys(substream->runtime->dma_area);
-       pr_debug("sst: period_cnt = %d\n", param.uc.pcm_params.period_count);
-       pr_debug("sst: sfreq= %d, wd_sz = %d\n",
+       pr_debug("period_cnt = %d\n", param.uc.pcm_params.period_count);
+       pr_debug("sfreq= %d, wd_sz = %d\n",
                 param.uc.pcm_params.sfreq, param.uc.pcm_params.pcm_wd_sz);
 
        str_params.sparams = param;
@@ -85,16 +88,16 @@ int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream)
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                str_params.ops = STREAM_OPS_PLAYBACK;
-               pr_debug("sst: Playbck stream,Device %d\n", stream->device);
+               pr_debug("Playbck stream,Device %d\n", stream->device);
        } else {
                str_params.ops = STREAM_OPS_CAPTURE;
                stream->device = SND_SST_DEVICE_CAPTURE;
-               pr_debug("sst: Capture stream,Device %d\n", stream->device);
+               pr_debug("Capture stream,Device %d\n", stream->device);
        }
        str_params.device_type = stream->device;
        ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_ALLOC,
                                        &str_params);
-       pr_debug("sst: SST_SND_PLAY/CAPTURE ret_val = %x\n",
+       pr_debug("SST_SND_PLAY/CAPTURE ret_val = %x\n",
                        ret_val);
        if (ret_val < 0)
                return ret_val;
@@ -102,7 +105,7 @@ int snd_intelmad_alloc_stream(struct snd_pcm_substream *substream)
        stream->stream_info.str_id = ret_val;
        stream->stream_status = INIT;
        stream->stream_info.buffer_ptr = 0;
-       pr_debug("sst: str id :  %d\n", stream->stream_info.str_id);
+       pr_debug("str id :  %d\n", stream->stream_info.str_id);
 
        return ret_val;
 }
@@ -113,7 +116,7 @@ int snd_intelmad_init_stream(struct snd_pcm_substream *substream)
        struct snd_intelmad *intelmaddata = snd_pcm_substream_chip(substream);
        int ret_val;
 
-       pr_debug("sst: setting buffer ptr param\n");
+       pr_debug("setting buffer ptr param\n");
        stream->stream_info.period_elapsed = period_elapsed;
        stream->stream_info.mad_substream = substream;
        stream->stream_info.buffer_ptr = 0;
@@ -121,7 +124,7 @@ int snd_intelmad_init_stream(struct snd_pcm_substream *substream)
        ret_val = intelmaddata->sstdrv_ops->control_set(SST_SND_STREAM_INIT,
                                        &stream->stream_info);
        if (ret_val)
-               pr_err("sst: control_set ret error %d\n", ret_val);
+               pr_err("control_set ret error %d\n", ret_val);
        return ret_val;
 
 }
@@ -146,7 +149,7 @@ int sst_sc_reg_access(struct sc_reg_access *sc_access,
                        retval = intel_scu_ipc_iowrite8(sc_access[i].reg_addr,
                                                        sc_access[i].value);
                        if (retval) {
-                               pr_err("sst: IPC write failed!!! %d\n", retval);
+                               pr_err("IPC write failed!!! %d\n", retval);
                                return retval;
                        }
                }
@@ -155,7 +158,7 @@ int sst_sc_reg_access(struct sc_reg_access *sc_access,
                        retval = intel_scu_ipc_ioread8(sc_access[i].reg_addr,
                                                        &(sc_access[i].value));
                        if (retval) {
-                               pr_err("sst: IPC read failed!!!!!%d\n", retval);
+                               pr_err("IPC read failed!!!!!%d\n", retval);
                                return retval;
                        }
                }
@@ -165,7 +168,7 @@ int sst_sc_reg_access(struct sc_reg_access *sc_access,
                                sc_access[i].reg_addr, sc_access[i].value,
                                sc_access[i].mask);
                        if (retval) {
-                               pr_err("sst: IPC Modify failed!!!%d\n", retval);
+                               pr_err("IPC Modify failed!!!%d\n", retval);
                                return retval;
                        }
                }
index f586d62ac9afa67eb3f2540021fa2a89a7189f01..7859225e3d60a87758593d33e4006116369f1031 100644 (file)
@@ -26,6 +26,8 @@
  *  This file contains the control operations of vendor 1
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/pci.h>
 #include <linux/file.h>
 #include "intel_sst.h"
@@ -151,7 +153,7 @@ static int fs_power_up_pb(unsigned int port)
        if (retval)
                return retval;
 
-       pr_debug("sst: in fs power up pb\n");
+       pr_debug("in fs power up pb\n");
        return fs_enable_audiodac(UNMUTE);
 }
 
@@ -173,7 +175,7 @@ static int fs_power_down_pb(void)
        if (retval)
                return retval;
 
-       pr_debug("sst: in fsl power down pb\n");
+       pr_debug("in fsl power down pb\n");
        return fs_enable_audiodac(UNMUTE);
 }
 
@@ -380,7 +382,7 @@ static int fs_set_pcm_audio_params(int sfreq, int word_size, int num_channel)
                sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
 
        }
-       pr_debug("sst: sfreq:%d,Register value = %x\n", sfreq, config1);
+       pr_debug("sfreq:%d,Register value = %x\n", sfreq, config1);
 
        if (word_size == 24) {
                sc_access[0].reg_addr  = AUDIOPORT1;
@@ -438,18 +440,18 @@ static int fs_set_selected_input_dev(u8 value)
 
        switch (value) {
        case AMIC:
-               pr_debug("sst: Selecting amic not supported in mono cfg\n");
+               pr_debug("Selecting amic not supported in mono cfg\n");
                return sst_sc_reg_access(sc_access_mic, PMIC_READ_MODIFY, 2);
                break;
 
        case HS_MIC:
-               pr_debug("sst: Selecting hsmic\n");
+               pr_debug("Selecting hsmic\n");
                return sst_sc_reg_access(sc_access_hsmic,
                                PMIC_READ_MODIFY, 2);
                break;
 
        case DMIC:
-               pr_debug("sst: Selecting dmic\n");
+               pr_debug("Selecting dmic\n");
                return sst_sc_reg_access(sc_access_dmic, PMIC_READ_MODIFY, 2);
                break;
 
@@ -505,7 +507,7 @@ static int fs_set_mute(int dev_id, u8 value)
                return retval;
 
 
-       pr_debug("sst: dev_id:0x%x value:0x%x\n", dev_id, value);
+       pr_debug("dev_id:0x%x value:0x%x\n", dev_id, value);
        switch (dev_id) {
        case PMIC_SND_DMIC_MUTE:
                sc_access[0].reg_addr = MICCTRL;
@@ -606,7 +608,7 @@ static int fs_set_vol(int dev_id, int value)
 
        switch (dev_id) {
        case PMIC_SND_LEFT_PB_VOL:
-               pr_debug("sst: PMIC_SND_LEFT_PB_VOL:%d\n", value);
+               pr_debug("PMIC_SND_LEFT_PB_VOL:%d\n", value);
                sc_access[0].value = sc_access[1].value = value;
                sc_access[0].reg_addr = AUD16;
                sc_access[1].reg_addr = AUD15;
@@ -616,7 +618,7 @@ static int fs_set_vol(int dev_id, int value)
                break;
 
        case PMIC_SND_RIGHT_PB_VOL:
-               pr_debug("sst: PMIC_SND_RIGHT_PB_VOL:%d\n", value);
+               pr_debug("PMIC_SND_RIGHT_PB_VOL:%d\n", value);
                sc_access[0].value = sc_access[1].value = value;
                sc_access[0].reg_addr = AUD17;
                sc_access[1].reg_addr = AUD15;
@@ -629,7 +631,7 @@ static int fs_set_vol(int dev_id, int value)
                reg_num = 2;
                break;
        case PMIC_SND_CAPTURE_VOL:
-               pr_debug("sst: PMIC_SND_CAPTURE_VOL:%d\n", value);
+               pr_debug("PMIC_SND_CAPTURE_VOL:%d\n", value);
                sc_access[0].reg_addr = MICLICTRL1;
                sc_access[1].reg_addr = MICLICTRL2;
                sc_access[2].reg_addr = DMICCTRL1;
@@ -726,17 +728,17 @@ static int fs_get_vol(int dev_id, int *value)
 
        switch (dev_id) {
        case PMIC_SND_CAPTURE_VOL:
-               pr_debug("sst: PMIC_SND_CAPTURE_VOL\n");
+               pr_debug("PMIC_SND_CAPTURE_VOL\n");
                sc_access.reg_addr = MICLICTRL1;
                mask = (MASK5|MASK4|MASK3|MASK2|MASK1|MASK0);
                break;
        case PMIC_SND_LEFT_PB_VOL:
-               pr_debug("sst: PMIC_SND_LEFT_PB_VOL\n");
+               pr_debug("PMIC_SND_LEFT_PB_VOL\n");
                sc_access.reg_addr = AUD16;
                mask = (MASK5|MASK4|MASK3|MASK2|MASK1|MASK0);
                break;
        case PMIC_SND_RIGHT_PB_VOL:
-               pr_debug("sst: PMIC_SND_RT_PB_VOL\n");
+               pr_debug("PMIC_SND_RT_PB_VOL\n");
                sc_access.reg_addr = AUD17;
                mask = (MASK5|MASK4|MASK3|MASK2|MASK1|MASK0);
                break;
@@ -745,9 +747,9 @@ static int fs_get_vol(int dev_id, int *value)
        }
 
        retval = sst_sc_reg_access(&sc_access, PMIC_READ, 1);
-       pr_debug("sst: value read = 0x%x\n", sc_access.value);
+       pr_debug("value read = 0x%x\n", sc_access.value);
        *value = (int) (sc_access.value & mask);
-       pr_debug("sst: value returned = 0x%x\n", *value);
+       pr_debug("value returned = 0x%x\n", *value);
        return retval;
 }
 
index 9de86b2f6b086d6bc4c148c3ad080bf53e51d141..62a932bf809a79add5ff7cbf38966b53eb249977 100644 (file)
@@ -25,6 +25,8 @@
  *  This file contains the control operations of vendor 2
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/pci.h>
 #include <linux/file.h>
 #include <asm/mrst.h>
@@ -150,11 +152,11 @@ static int mx_init_capture_card(void)
        retval = sst_sc_reg_access(sc_access, PMIC_WRITE, 8);
        if (0 != retval) {
                /* pmic communication fails */
-               pr_debug("sst: pmic commn failed\n");
+               pr_debug("pmic commn failed\n");
                return retval;
        }
 
-       pr_debug("sst: Capture configuration complete!!\n");
+       pr_debug("Capture configuration complete!!\n");
        return 0;
 }
 
@@ -174,11 +176,11 @@ static int mx_init_playback_card(void)
        retval = sst_sc_reg_access(sc_access, PMIC_WRITE, 9);
        if (0 != retval) {
                /* pmic communication fails */
-               pr_debug("sst: pmic commn failed\n");
+               pr_debug("pmic commn failed\n");
                return retval;
        }
 
-       pr_debug("sst: Playback configuration complete!!\n");
+       pr_debug("Playback configuration complete!!\n");
        return 0;
 }
 
@@ -204,7 +206,7 @@ static int mx_enable_audiodac(int value)
        retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 2);
        if (retval)
                return retval;
-       pr_debug("sst: mute status = %d", snd_pmic_ops_mx.mute_status);
+       pr_debug("mute status = %d\n", snd_pmic_ops_mx.mute_status);
        if (snd_pmic_ops_mx.mute_status == MUTE ||
                                snd_pmic_ops_mx.master_mute == MUTE)
                return retval;
@@ -412,7 +414,7 @@ static int mx_set_pcm_voice_params(void)
                if (retval)
                        return retval;
        }
-       pr_debug("sst: SST DBG mx_set_pcm_voice_params called\n");
+       pr_debug("SST DBG:mx_set_pcm_voice_params called\n");
        return sst_sc_reg_access(sc_access, PMIC_WRITE, 44);
 }
 
@@ -529,7 +531,7 @@ static int mx_set_selected_output_dev(u8 dev_id)
                        return retval;
        }
 
-       pr_debug("sst: mx_set_selected_output_dev dev_id:0x%x\n", dev_id);
+       pr_debug("mx_set_selected_output_dev dev_id:0x%x\n", dev_id);
        snd_pmic_ops_mx.output_dev_id = dev_id;
        switch (dev_id) {
        case STEREO_HEADPHONE:
@@ -549,7 +551,7 @@ static int mx_set_selected_output_dev(u8 dev_id)
                num_reg = 1;
                break;
        case RECEIVER:
-               pr_debug("sst: RECEIVER Koski selected\n");
+               pr_debug("RECEIVER Koski selected\n");
 
                /* configuration - AS enable, receiver enable */
                sc_access[0].reg_addr = 0xFF;
@@ -559,7 +561,7 @@ static int mx_set_selected_output_dev(u8 dev_id)
                num_reg = 1;
                break;
        default:
-               pr_err("sst: Not a valid output dev\n");
+               pr_err("Not a valid output dev\n");
                return 0;
        }
        return sst_sc_reg_access(sc_access, PMIC_WRITE, num_reg);
@@ -598,7 +600,7 @@ static int mx_set_selected_input_dev(u8 dev_id)
                        return retval;
        }
        snd_pmic_ops_mx.input_dev_id = dev_id;
-       pr_debug("sst: mx_set_selected_input_dev dev_id:0x%x\n", dev_id);
+       pr_debug("mx_set_selected_input_dev dev_id:0x%x\n", dev_id);
 
        switch (dev_id) {
        case AMIC:
@@ -646,7 +648,7 @@ static int mx_set_mute(int dev_id, u8 value)
        }
 
 
-       pr_debug("sst: set_mute dev_id:0x%x , value:%d\n", dev_id, value);
+       pr_debug("set_mute dev_id:0x%x , value:%d\n", dev_id, value);
 
        switch (dev_id) {
        case PMIC_SND_DMIC_MUTE:
@@ -760,7 +762,7 @@ static int mx_set_vol(int dev_id, int value)
                if (retval)
                        return retval;
        }
-       pr_debug("sst: set_vol dev_id:0x%x ,value:%d\n", dev_id, value);
+       pr_debug("set_vol dev_id:0x%x ,value:%d\n", dev_id, value);
        switch (dev_id) {
        case PMIC_SND_RECEIVER_VOL:
                return 0;
@@ -875,7 +877,7 @@ static int mx_get_vol(int dev_id, int *value)
        if (retval)
                return retval;
        *value = -(sc_access.value & mask);
-       pr_debug("sst: get volume value extracted %d\n", *value);
+       pr_debug("get volume value extracted %d\n", *value);
        return retval;
 }
 
index 3a7de769842a41288c93fb525829a3615c4fc224..81cb9d70870bd2b30bdca519f0750b9853f69986 100644 (file)
@@ -26,6 +26,8 @@
  *  This file contains the control operations of vendor 3
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/pci.h>
 #include <linux/file.h>
 #include "intel_sst.h"
@@ -120,7 +122,7 @@ static int nc_init_card(void)
        snd_pmic_ops_nc.master_mute = UNMUTE;
        snd_pmic_ops_nc.mute_status = UNMUTE;
        sst_sc_reg_access(sc_access, PMIC_WRITE, 26);
-       pr_debug("sst: init complete!!\n");
+       pr_debug("init complete!!\n");
        return 0;
 }
 
@@ -169,7 +171,7 @@ static int nc_power_up_pb(unsigned int port)
        nc_enable_audiodac(MUTE);
        msleep(30);
 
-       pr_debug("sst: powering up pb....\n");
+       pr_debug("powering up pb....\n");
 
        sc_access[0].reg_addr = VAUDIOCNT;
        sc_access[0].value = 0x27;
@@ -222,7 +224,7 @@ static int nc_power_up_cp(unsigned int port)
                return retval;
 
 
-       pr_debug("sst: powering up cp....\n");
+       pr_debug("powering up cp....\n");
 
        if (port == 0xFF)
                return 0;
@@ -275,7 +277,7 @@ static int nc_power_down(void)
        nc_enable_audiodac(MUTE);
 
 
-       pr_debug("sst: powering dn nc_power_down ....\n");
+       pr_debug("powering dn nc_power_down ....\n");
 
        msleep(30);
 
@@ -324,7 +326,7 @@ static int nc_power_down_pb(void)
        if (retval)
                return retval;
 
-       pr_debug("sst: powering dn pb....\n");
+       pr_debug("powering dn pb....\n");
 
        nc_enable_audiodac(MUTE);
 
@@ -370,7 +372,7 @@ static int nc_power_down_cp(void)
        if (retval)
                return retval;
 
-       pr_debug("sst: powering dn cp....\n");
+       pr_debug("powering dn cp....\n");
        return sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
 }
 
@@ -400,7 +402,7 @@ static int nc_set_pcm_voice_params(void)
                return retval;
 
        sst_sc_reg_access(sc_access, PMIC_WRITE, 14);
-       pr_debug("sst: Voice parameters set successfully!!\n");
+       pr_debug("Voice parameters set successfully!!\n");
        return 0;
 }
 
@@ -451,20 +453,20 @@ static int nc_set_pcm_audio_params(int sfreq, int word_size, int num_channel)
 
                sc_access.value = 0x07;
                sc_access.reg_addr = RMUTE;
-               pr_debug("sst: RIGHT_HP_MUTE value%d\n", sc_access.value);
+               pr_debug("RIGHT_HP_MUTE value%d\n", sc_access.value);
                sc_access.mask = MASK2;
                sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1);
        } else {
                sc_access.value = 0x00;
                sc_access.reg_addr = RMUTE;
-               pr_debug("sst: RIGHT_HP_MUTE value %d\n", sc_access.value);
+               pr_debug("RIGHT_HP_MUTE value %d\n", sc_access.value);
                sc_access.mask = MASK2;
                sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1);
 
 
        }
 
-       pr_debug("sst: word_size = %d\n", word_size);
+       pr_debug("word_size = %d\n", word_size);
 
        if (word_size == 24) {
                sc_access.reg_addr = AUDIOPORT2;
@@ -477,7 +479,7 @@ static int nc_set_pcm_audio_params(int sfreq, int word_size, int num_channel)
        }
        sst_sc_reg_access(&sc_access, PMIC_READ_MODIFY, 1);
 
-       pr_debug("sst: word_size = %d\n", word_size);
+       pr_debug("word_size = %d\n", word_size);
        sc_access.reg_addr = AUDIOPORT1;
        sc_access.mask = MASK5|MASK4|MASK1|MASK0;
        if (word_size == 16)
@@ -508,7 +510,7 @@ static int nc_set_selected_output_dev(u8 value)
                retval = nc_init_card();
        if (retval)
                return retval;
-       pr_debug("sst: nc set selected output:%d\n", value);
+       pr_debug("nc set selected output:%d\n", value);
        switch (value) {
        case STEREO_HEADPHONE:
                retval = sst_sc_reg_access(sc_access_HP, PMIC_WRITE, 2);
@@ -517,7 +519,7 @@ static int nc_set_selected_output_dev(u8 value)
                retval = sst_sc_reg_access(sc_access_IS, PMIC_WRITE, 2);
                break;
        default:
-               pr_err("sst: rcvd illegal request: %d\n", value);
+               pr_err("rcvd illegal request: %d\n", value);
                return -EINVAL;
        }
        return retval;
@@ -541,7 +543,7 @@ static int nc_audio_init(void)
        };
 
        sst_sc_reg_access(sc_access, PMIC_WRITE, 12);
-       pr_debug("sst: Audio Init successfully!!\n");
+       pr_debug("Audio Init successfully!!\n");
 
        /*set output device */
        nc_set_selected_output_dev(snd_pmic_ops_nc.output_dev_id);
@@ -549,13 +551,13 @@ static int nc_audio_init(void)
        if (snd_pmic_ops_nc.num_channel == 1) {
                sc_acces.value = 0x07;
                sc_acces.reg_addr = RMUTE;
-               pr_debug("sst: RIGHT_HP_MUTE value%d\n", sc_acces.value);
+               pr_debug("RIGHT_HP_MUTE value%d\n", sc_acces.value);
                sc_acces.mask = MASK2;
                sst_sc_reg_access(&sc_acces, PMIC_READ_MODIFY, 1);
        } else {
                sc_acces.value = 0x00;
                sc_acces.reg_addr = RMUTE;
-               pr_debug("sst: RIGHT_HP_MUTE value%d\n", sc_acces.value);
+               pr_debug("RIGHT_HP_MUTE value%d\n", sc_acces.value);
                sc_acces.mask = MASK2;
                sst_sc_reg_access(&sc_acces, PMIC_READ_MODIFY, 1);
        }
@@ -629,11 +631,11 @@ static int nc_set_mute(int dev_id, u8 value)
        if (retval)
                return retval;
 
-       pr_debug("sst: set device id::%d, value %d\n", dev_id, value);
+       pr_debug("set device id::%d, value %d\n", dev_id, value);
 
        switch (dev_id) {
        case PMIC_SND_MUTE_ALL:
-               pr_debug("sst: PMIC_SND_MUTE_ALL value %d\n", value);
+               pr_debug("PMIC_SND_MUTE_ALL value %d\n", value);
                snd_pmic_ops_nc.mute_status = value;
                snd_pmic_ops_nc.master_mute = value;
                if (value == UNMUTE) {
@@ -669,7 +671,7 @@ static int nc_set_mute(int dev_id, u8 value)
                }
                break;
        case PMIC_SND_HP_MIC_MUTE:
-               pr_debug("sst: PMIC_SND_HPMIC_MUTE value %d\n", value);
+               pr_debug("PMIC_SND_HPMIC_MUTE value %d\n", value);
                if (value == UNMUTE) {
                        /* unmute the system, set the 6th bit to one */
                        sc_access[0].value = 0x00;
@@ -682,7 +684,7 @@ static int nc_set_mute(int dev_id, u8 value)
                retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
                break;
        case PMIC_SND_AMIC_MUTE:
-               pr_debug("sst: PMIC_SND_AMIC_MUTE value %d\n", value);
+               pr_debug("PMIC_SND_AMIC_MUTE value %d\n", value);
                if (value == UNMUTE) {
                        /* unmute the system, set the 6th bit to one */
                        sc_access[0].value = 0x00;
@@ -696,7 +698,7 @@ static int nc_set_mute(int dev_id, u8 value)
                break;
 
        case PMIC_SND_DMIC_MUTE:
-               pr_debug("sst: INPUT_MUTE_DMIC value%d\n", value);
+               pr_debug("INPUT_MUTE_DMIC value%d\n", value);
                if (value == UNMUTE) {
                        /* unmute the system, set the 6th bit to one */
                        sc_access[1].value = 0x00;
@@ -724,13 +726,13 @@ static int nc_set_mute(int dev_id, u8 value)
 
                if (dev_id == PMIC_SND_LEFT_HP_MUTE) {
                        sc_access[0].reg_addr = LMUTE;
-                       pr_debug("sst: LEFT_HP_MUTE value %d\n",
+                       pr_debug("LEFT_HP_MUTE value %d\n",
                                        sc_access[0].value);
                } else {
                        if (snd_pmic_ops_nc.num_channel == 1)
                                sc_access[0].value = 0x04;
                        sc_access[0].reg_addr = RMUTE;
-                       pr_debug("sst: RIGHT_HP_MUTE value %d\n",
+                       pr_debug("RIGHT_HP_MUTE value %d\n",
                                        sc_access[0].value);
                }
                sc_access[0].mask = MASK2;
@@ -743,7 +745,7 @@ static int nc_set_mute(int dev_id, u8 value)
                else
                        sc_access[0].value = 0x03;
                sc_access[0].reg_addr = LMUTE;
-               pr_debug("sst: SPEAKER_MUTE %d\n", sc_access[0].value);
+               pr_debug("SPEAKER_MUTE %d\n", sc_access[0].value);
                sc_access[0].mask = MASK1;
                retval = sst_sc_reg_access(sc_access, PMIC_READ_MODIFY, 1);
                break;
@@ -764,10 +766,10 @@ static int nc_set_vol(int dev_id, int value)
        if (retval)
                return retval;
 
-       pr_debug("sst: set volume:%d\n", dev_id);
+       pr_debug("set volume:%d\n", dev_id);
        switch (dev_id) {
        case PMIC_SND_CAPTURE_VOL:
-               pr_debug("sst: PMIC_SND_CAPTURE_VOL:value::%d\n", value);
+               pr_debug("PMIC_SND_CAPTURE_VOL:value::%d\n", value);
                sc_access[0].value = sc_access[1].value =
                                        sc_access[2].value = -value;
                sc_access[0].mask = sc_access[1].mask = sc_access[2].mask =
@@ -779,7 +781,7 @@ static int nc_set_vol(int dev_id, int value)
                break;
 
        case PMIC_SND_LEFT_PB_VOL:
-               pr_debug("sst: PMIC_SND_LEFT_HP_VOL %d\n", value);
+               pr_debug("PMIC_SND_LEFT_HP_VOL %d\n", value);
                sc_access[0].value = -value;
                sc_access[0].reg_addr  = AUDIOLVOL;
                sc_access[0].mask =
@@ -788,7 +790,7 @@ static int nc_set_vol(int dev_id, int value)
                break;
 
        case PMIC_SND_RIGHT_PB_VOL:
-               pr_debug("sst: PMIC_SND_RIGHT_HP_VOL value %d\n", value);
+               pr_debug("PMIC_SND_RIGHT_HP_VOL value %d\n", value);
                if (snd_pmic_ops_nc.num_channel == 1) {
                        sc_access[0].value = 0x04;
                    sc_access[0].reg_addr = RMUTE;
@@ -821,11 +823,11 @@ static int nc_set_selected_input_dev(u8 value)
                return retval;
        snd_pmic_ops_nc.input_dev_id = value;
 
-       pr_debug("sst: nc set selected input:%d\n", value);
+       pr_debug("nc set selected input:%d\n", value);
 
        switch (value) {
        case AMIC:
-               pr_debug("sst: Selecting AMIC\n");
+               pr_debug("Selecting AMIC\n");
                sc_access[0].reg_addr = 0x107;
                sc_access[0].value = 0x40;
                sc_access[0].mask =  MASK6|MASK4|MASK3|MASK1|MASK0;
@@ -842,7 +844,7 @@ static int nc_set_selected_input_dev(u8 value)
                break;
 
        case HS_MIC:
-               pr_debug("sst: Selecting HS_MIC\n");
+               pr_debug("Selecting HS_MIC\n");
                sc_access[0].reg_addr = 0x107;
                sc_access[0].mask =  MASK6|MASK4|MASK3|MASK1|MASK0;
                sc_access[0].value = 0x10;
@@ -859,7 +861,7 @@ static int nc_set_selected_input_dev(u8 value)
                break;
 
        case DMIC:
-               pr_debug("sst: DMIC\n");
+               pr_debug("DMIC\n");
                sc_access[0].reg_addr = 0x107;
                sc_access[0].mask = MASK6|MASK4|MASK3|MASK1|MASK0;
                sc_access[0].value = 0x0B;
@@ -890,23 +892,23 @@ static int nc_get_mute(int dev_id, u8 *value)
        if (retval)
                return retval;
 
-       pr_debug("sst: get mute::%d\n", dev_id);
+       pr_debug("get mute::%d\n", dev_id);
 
        switch (dev_id) {
        case PMIC_SND_AMIC_MUTE:
-               pr_debug("sst: PMIC_SND_INPUT_MUTE_MIC1\n");
+               pr_debug("PMIC_SND_INPUT_MUTE_MIC1\n");
                sc_access.reg_addr = LILSEL;
                mask = MASK6;
                break;
        case PMIC_SND_HP_MIC_MUTE:
-               pr_debug("sst: PMIC_SND_INPUT_MUTE_MIC2\n");
+               pr_debug("PMIC_SND_INPUT_MUTE_MIC2\n");
                sc_access.reg_addr = LIRSEL;
                mask = MASK6;
                break;
        case PMIC_SND_LEFT_HP_MUTE:
        case PMIC_SND_RIGHT_HP_MUTE:
                mask = MASK2;
-               pr_debug("sst: PMIC_SN_LEFT/RIGHT_HP_MUTE\n");
+               pr_debug("PMIC_SN_LEFT/RIGHT_HP_MUTE\n");
                if (dev_id == PMIC_SND_RIGHT_HP_MUTE)
                        sc_access.reg_addr = RMUTE;
                else
@@ -914,12 +916,12 @@ static int nc_get_mute(int dev_id, u8 *value)
                break;
 
        case PMIC_SND_LEFT_SPEAKER_MUTE:
-               pr_debug("sst: PMIC_MONO_EARPIECE_MUTE\n");
+               pr_debug("PMIC_MONO_EARPIECE_MUTE\n");
                sc_access.reg_addr = RMUTE;
                mask = MASK1;
                break;
        case PMIC_SND_DMIC_MUTE:
-               pr_debug("sst: PMIC_SND_INPUT_MUTE_DMIC\n");
+               pr_debug("PMIC_SND_INPUT_MUTE_DMIC\n");
                sc_access.reg_addr = 0x105;
                mask = MASK6;
                break;
@@ -928,16 +930,16 @@ static int nc_get_mute(int dev_id, u8 *value)
 
        }
        retval = sst_sc_reg_access(&sc_access, PMIC_READ, 1);
-       pr_debug("sst: reg value = %d\n", sc_access.value);
+       pr_debug("reg value = %d\n", sc_access.value);
        if (retval)
                return retval;
        *value = (sc_access.value) & mask;
-       pr_debug("sst: masked value = %d\n", *value);
+       pr_debug("masked value = %d\n", *value);
        if (*value)
                *value = 0;
        else
                *value = 1;
-       pr_debug("sst: value returned = 0x%x\n", *value);
+       pr_debug("value returned = 0x%x\n", *value);
        return retval;
 }
 
@@ -953,19 +955,19 @@ static int nc_get_vol(int dev_id, int *value)
 
        switch (dev_id) {
        case PMIC_SND_CAPTURE_VOL:
-               pr_debug("sst: PMIC_SND_INPUT_CAPTURE_VOL\n");
+               pr_debug("PMIC_SND_INPUT_CAPTURE_VOL\n");
                sc_access.reg_addr =  LILSEL;
                mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5);
                break;
 
        case PMIC_SND_RIGHT_PB_VOL:
-               pr_debug("sst: GET_VOLUME_PMIC_LEFT_HP_VOL\n");
+               pr_debug("GET_VOLUME_PMIC_LEFT_HP_VOL\n");
                sc_access.reg_addr = AUDIOLVOL;
                mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6);
                break;
 
        case PMIC_SND_LEFT_PB_VOL:
-               pr_debug("sst: GET_VOLUME_PMIC_RIGHT_HP_VOL\n");
+               pr_debug("GET_VOLUME_PMIC_RIGHT_HP_VOL\n");
                sc_access.reg_addr = AUDIORVOL;
                mask = (MASK0|MASK1|MASK2|MASK3|MASK4|MASK5|MASK6);
                break;
@@ -975,9 +977,9 @@ static int nc_get_vol(int dev_id, int *value)
 
        }
        retval = sst_sc_reg_access(&sc_access, PMIC_READ, 1);
-       pr_debug("sst: value read = 0x%x\n", sc_access.value);
+       pr_debug("value read = 0x%x\n", sc_access.value);
        *value = -((sc_access.value) & mask);
-       pr_debug("sst: get vol value returned = %d\n", *value);
+       pr_debug("get vol value returned = %d\n", *value);
        return retval;
 }
 
index bb3606faf20e975bc76db09d488f1615a5b73244..07a89ecfcc2b7bdceaacb276504d14cb5c4001a6 100644 (file)
@@ -41,11 +41,11 @@ obj-$(CONFIG_FB_MSM_EBI2) += ebi2_lcd.o
 obj-$(CONFIG_FB_MSM_LCDC) += lcdc.o
 
 # MDDI
-msm_mddi-objs := mddi.o mddihost.o mddihosti.o
+msm_mddi-y := mddi.o mddihost.o mddihosti.o
 obj-$(CONFIG_FB_MSM_MDDI) += msm_mddi.o
 
 # External MDDI
-msm_mddi_ext-objs := mddihost_e.o mddi_ext.o
+msm_mddi_ext-y := mddihost_e.o mddi_ext.o
 obj-$(CONFIG_FB_MSM_EXTMDDI) += msm_mddi_ext.o
 
 # TVEnc
index 2fdb3e01460df049b40ed057c08b1732f6a6aa17..6540864216c8fd1914544f5d988aef8082742250 100644 (file)
@@ -130,10 +130,8 @@ err_out_exit:
 
 void pohmelfs_crypto_engine_exit(struct pohmelfs_crypto_engine *e)
 {
-       if (e->hash)
-               crypto_free_hash(e->hash);
-       if (e->cipher)
-               crypto_free_ablkcipher(e->cipher);
+       crypto_free_hash(e->hash);
+       crypto_free_ablkcipher(e->cipher);
        kfree(e->data);
 }
 
index 494f180acc262df898a1c708c102e1a214df69b5..4cc7b418c91e59712be990b2d6760514fb329af9 100644 (file)
@@ -1507,7 +1507,7 @@ static void rtl8192_tx_isr(struct urb *tx_urb)
        {
                //
                // Handle HW Beacon:
-               // We had transfer our beacon frame to host controler at this moment.
+               // We had transfer our beacon frame to host controller at this moment.
                //
                //
                // Caution:
diff --git a/drivers/staging/ste_rmi4/Kconfig b/drivers/staging/ste_rmi4/Kconfig
new file mode 100644 (file)
index 0000000..95fd5a9
--- /dev/null
@@ -0,0 +1,9 @@
+config TOUCHSCREEN_SYNAPTICS_I2C_RMI4
+       tristate "Synaptics i2c rmi4 touchscreen"
+       depends on I2C
+       help
+         Say Y here if you have a Synaptics RMI4 and
+         want to enable support for the built-in touchscreen.
+
+         To compile this driver as a module, choose M here: the
+         module will be called synaptics_rmi4_ts.
diff --git a/drivers/staging/ste_rmi4/Makefile b/drivers/staging/ste_rmi4/Makefile
new file mode 100644 (file)
index 0000000..6cce2ed
--- /dev/null
@@ -0,0 +1,4 @@
+#
+# Makefile for the RMI4 touchscreen driver.
+#
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += synaptics_i2c_rmi4.o
diff --git a/drivers/staging/ste_rmi4/TODO b/drivers/staging/ste_rmi4/TODO
new file mode 100644 (file)
index 0000000..9be2437
--- /dev/null
@@ -0,0 +1,7 @@
+TODO
+----
+
+Wait for the official upstream synaptics rmi4 clearpad drivers as promised over the past few months
+Merge any device support needed from this driver into it
+Delete this driver
+
diff --git a/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.c
new file mode 100644 (file)
index 0000000..e8f047e
--- /dev/null
@@ -0,0 +1,1179 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) I2C Physical Layer Driver.
+ * Copyright (c) 2007-2010, Synaptics Incorporated
+ *
+ * Author: Js HA <js.ha@stericsson.com> for ST-Ericsson
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * Copyright 2010 (c) ST-Ericsson AB
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ *#############################################################################
+ */
+
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/regulator/consumer.h>
+#include "synaptics_i2c_rmi4.h"
+
+/* TODO: for multiple device support will need a per-device mutex */
+#define DRIVER_NAME "synaptics_rmi4_i2c"
+
+#define MAX_ERROR_REPORT       6
+#define MAX_TOUCH_MAJOR                15
+#define MAX_RETRY_COUNT                5
+#define STD_QUERY_LEN          21
+#define PAGE_LEN               2
+#define DATA_BUF_LEN           32
+#define BUF_LEN                        37
+#define QUERY_LEN              9
+#define DATA_LEN               12
+#define HAS_TAP                        0x01
+#define HAS_PALMDETECT         0x01
+#define HAS_ROTATE             0x02
+#define HAS_TAPANDHOLD         0x02
+#define HAS_DOUBLETAP          0x04
+#define HAS_EARLYTAP           0x08
+#define HAS_RELEASE            0x08
+#define HAS_FLICK              0x10
+#define HAS_PRESS              0x20
+#define HAS_PINCH              0x40
+
+#define MASK_16BIT             0xFFFF
+#define MASK_8BIT              0xFF
+#define MASK_7BIT              0x7F
+#define MASK_5BIT              0x1F
+#define MASK_4BIT              0x0F
+#define MASK_3BIT              0x07
+#define MASK_2BIT              0x03
+#define TOUCHPAD_CTRL_INTR     0x8
+#define PDT_START_SCAN_LOCATION (0x00E9)
+#define PDT_END_SCAN_LOCATION  (0x000A)
+#define PDT_ENTRY_SIZE         (0x0006)
+#define RMI4_NUMBER_OF_MAX_FINGERS             (8)
+#define SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM       (0x11)
+#define SYNAPTICS_RMI4_DEVICE_CONTROL_FUNC_NUM (0x01)
+
+/**
+ * struct synaptics_rmi4_fn_desc - contains the funtion descriptor information
+ * @query_base_addr: base address for query
+ * @cmd_base_addr: base address for command
+ * @ctrl_base_addr: base address for control
+ * @data_base_addr: base address for data
+ * @intr_src_count: count for the interrupt source
+ * @fn_number: function number
+ *
+ * This structure is used to gives the function descriptor information
+ * of the particular functionality.
+ */
+struct synaptics_rmi4_fn_desc {
+       unsigned char   query_base_addr;
+       unsigned char   cmd_base_addr;
+       unsigned char   ctrl_base_addr;
+       unsigned char   data_base_addr;
+       unsigned char   intr_src_count;
+       unsigned char   fn_number;
+};
+
+/**
+ * struct synaptics_rmi4_fn - contains the funtion information
+ * @fn_number: function number
+ * @num_of_data_sources: number of data sources
+ * @num_of_data_points: number of fingers touched
+ * @size_of_data_register_block: data register block size
+ * @index_to_intr_reg: index for interrupt register
+ * @intr_mask: interrupt mask value
+ * @fn_desc: variable for function descriptor structure
+ * @link: linked list for function descriptors
+ *
+ * This structure gives information about the number of data sources and
+ * the number of data registers associated with the function.
+ */
+struct synaptics_rmi4_fn {
+       unsigned char           fn_number;
+       unsigned char           num_of_data_sources;
+       unsigned char           num_of_data_points;
+       unsigned char           size_of_data_register_block;
+       unsigned char           index_to_intr_reg;
+       unsigned char           intr_mask;
+       struct synaptics_rmi4_fn_desc   fn_desc;
+       struct list_head        link;
+};
+
+/**
+ * struct synaptics_rmi4_device_info - contains the rmi4 device information
+ * @version_major: protocol major version number
+ * @version_minor: protocol minor version number
+ * @manufacturer_id: manufacturer identification byte
+ * @product_props: product properties information
+ * @product_info: product info array
+ * @date_code: device manufacture date
+ * @tester_id: tester id array
+ * @serial_number: serial number for that device
+ * @product_id_string: product id for the device
+ * @support_fn_list: linked list for device information
+ *
+ * This structure gives information about the number of data sources and
+ * the number of data registers associated with the function.
+ */
+struct synaptics_rmi4_device_info {
+       unsigned int            version_major;
+       unsigned int            version_minor;
+       unsigned char           manufacturer_id;
+       unsigned char           product_props;
+       unsigned char           product_info[2];
+       unsigned char           date_code[3];
+       unsigned short          tester_id;
+       unsigned short          serial_number;
+       unsigned char           product_id_string[11];
+       struct list_head        support_fn_list;
+};
+
+/**
+ * struct synaptics_rmi4_data - contains the rmi4 device data
+ * @rmi4_mod_info: structure variable for rmi4 device info
+ * @input_dev: pointer for input device
+ * @i2c_client: pointer for i2c client
+ * @board: constant pointer for touch platform data
+ * @fn_list_mutex: mutex for funtion list
+ * @rmi4_page_mutex: mutex for rmi4 page
+ * @current_page: variable for integer
+ * @number_of_interrupt_register: interrupt registers count
+ * @fn01_ctrl_base_addr: control base address for fn01
+ * @fn01_query_base_addr: query base address for fn01
+ * @fn01_data_base_addr: data base address for fn01
+ * @sensor_max_x: sensor maximum x value
+ * @sensor_max_y: sensor maximum y value
+ * @regulator: pointer to the regulator structure
+ * @wait: wait queue structure variable
+ * @touch_stopped: flag to stop the thread function
+ *
+ * This structure gives the device data information.
+ */
+struct synaptics_rmi4_data {
+       struct synaptics_rmi4_device_info rmi4_mod_info;
+       struct input_dev        *input_dev;
+       struct i2c_client       *i2c_client;
+       const struct synaptics_rmi4_platform_data *board;
+       struct mutex            fn_list_mutex;
+       struct mutex            rmi4_page_mutex;
+       int                     current_page;
+       unsigned int            number_of_interrupt_register;
+       unsigned short          fn01_ctrl_base_addr;
+       unsigned short          fn01_query_base_addr;
+       unsigned short          fn01_data_base_addr;
+       int                     sensor_max_x;
+       int                     sensor_max_y;
+       struct regulator        *regulator;
+       wait_queue_head_t       wait;
+       bool                    touch_stopped;
+};
+
+/**
+ * synaptics_rmi4_set_page() - sets the page
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @address: set the address of the page
+ *
+ * This function is used to set the page and returns integer.
+ */
+static int synaptics_rmi4_set_page(struct synaptics_rmi4_data *pdata,
+                                       unsigned int address)
+{
+       unsigned char   txbuf[PAGE_LEN];
+       int             retval;
+       unsigned int    page;
+       struct i2c_client *i2c = pdata->i2c_client;
+
+       page    = ((address >> 8) & MASK_8BIT);
+       if (page != pdata->current_page) {
+               txbuf[0]        = MASK_8BIT;
+               txbuf[1]        = page;
+               retval  = i2c_master_send(i2c, txbuf, PAGE_LEN);
+               if (retval != PAGE_LEN)
+                       dev_err(&i2c->dev, "%s:failed:%d\n", __func__, retval);
+               else
+                       pdata->current_page = page;
+       } else
+               retval = PAGE_LEN;
+       return retval;
+}
+/**
+ * synaptics_rmi4_i2c_block_read() - read the block of data
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @address: read the block of data from this offset
+ * @valp: pointer to a buffer containing the data to be read
+ * @size: number of bytes to read
+ *
+ * This function is to read the block of data and returns integer.
+ */
+static int synaptics_rmi4_i2c_block_read(struct synaptics_rmi4_data *pdata,
+                                               unsigned short address,
+                                               unsigned char *valp, int size)
+{
+       int retval = 0;
+       int retry_count = 0;
+       int index;
+       struct i2c_client *i2c = pdata->i2c_client;
+
+       mutex_lock(&(pdata->rmi4_page_mutex));
+       retval = synaptics_rmi4_set_page(pdata, address);
+       if (retval != PAGE_LEN)
+               goto exit;
+       index = address & MASK_8BIT;
+retry:
+       retval = i2c_smbus_read_i2c_block_data(i2c, index, size, valp);
+       if (retval != size) {
+               if (++retry_count == MAX_RETRY_COUNT)
+                       dev_err(&i2c->dev,
+                               "%s:address 0x%04x size %d failed:%d\n",
+                                       __func__, address, size, retval);
+               else {
+                       synaptics_rmi4_set_page(pdata, address);
+                       goto retry;
+               }
+       }
+exit:
+       mutex_unlock(&(pdata->rmi4_page_mutex));
+       return retval;
+}
+
+/**
+ * synaptics_rmi4_i2c_byte_write() - write the single byte data
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @address: write the block of data from this offset
+ * @data: data to be write
+ *
+ * This function is to write the single byte data and returns integer.
+ */
+static int synaptics_rmi4_i2c_byte_write(struct synaptics_rmi4_data *pdata,
+                                               unsigned short address,
+                                               unsigned char data)
+{
+       unsigned char txbuf[2];
+       int retval = 0;
+       struct i2c_client *i2c = pdata->i2c_client;
+
+       /* Can't have anyone else changing the page behind our backs */
+       mutex_lock(&(pdata->rmi4_page_mutex));
+
+       retval = synaptics_rmi4_set_page(pdata, address);
+       if (retval != PAGE_LEN)
+               goto exit;
+       txbuf[0]        = address & MASK_8BIT;
+       txbuf[1]        = data;
+       retval          = i2c_master_send(pdata->i2c_client, txbuf, 2);
+       /* Add in retry on writes only in certian error return values */
+       if (retval != 2) {
+               dev_err(&i2c->dev, "%s:failed:%d\n", __func__, retval);
+               retval = -EIO;
+       } else
+               retval = 1;
+exit:
+       mutex_unlock(&(pdata->rmi4_page_mutex));
+       return retval;
+}
+
+/**
+ * synpatics_rmi4_touchpad_report() - reports for the rmi4 touchpad device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @rfi: pointer to synaptics_rmi4_fn structure
+ *
+ * This function calls to reports for the rmi4 touchpad device
+ */
+static int synpatics_rmi4_touchpad_report(struct synaptics_rmi4_data *pdata,
+                                               struct synaptics_rmi4_fn *rfi)
+{
+       /* number of touch points - fingers down in this case */
+       int     touch_count = 0;
+       int     finger;
+       int     fingers_supported;
+       int     finger_registers;
+       int     reg;
+       int     finger_shift;
+       int     finger_status;
+       int     retval;
+       unsigned short  data_base_addr;
+       unsigned short  data_offset;
+       unsigned char   data_reg_blk_size;
+       unsigned char   values[2];
+       unsigned char   data[DATA_LEN];
+       int     x[RMI4_NUMBER_OF_MAX_FINGERS];
+       int     y[RMI4_NUMBER_OF_MAX_FINGERS];
+       int     wx[RMI4_NUMBER_OF_MAX_FINGERS];
+       int     wy[RMI4_NUMBER_OF_MAX_FINGERS];
+       struct  i2c_client *client = pdata->i2c_client;
+
+       /* get 2D sensor finger data */
+       /*
+        * First get the finger status field - the size of the finger status
+        * field is determined by the number of finger supporte - 2 bits per
+        * finger, so the number of registers to read is:
+        * registerCount = ceil(numberOfFingers/4).
+        * Read the required number of registers and check each 2 bit field to
+        * determine if a finger is down:
+        *      00 = finger not present,
+        *      01 = finger present and data accurate,
+        *      10 = finger present but data may not be accurate,
+        *      11 = reserved for product use.
+        */
+       fingers_supported       = rfi->num_of_data_points;
+       finger_registers        = (fingers_supported + 3)/4;
+       data_base_addr          = rfi->fn_desc.data_base_addr;
+       retval = synaptics_rmi4_i2c_block_read(pdata, data_base_addr, values,
+                                                       finger_registers);
+       if (retval != finger_registers) {
+               dev_err(&client->dev, "%s:read status registers failed\n",
+                                                               __func__);
+               return 0;
+       }
+       /*
+        * For each finger present, read the proper number of registers
+        * to get absolute data.
+        */
+       data_reg_blk_size = rfi->size_of_data_register_block;
+       for (finger = 0; finger < fingers_supported; finger++) {
+               /* determine which data byte the finger status is in */
+               reg = finger/4;
+               /* bit shift to get finger's status */
+               finger_shift    = (finger % 4) * 2;
+               finger_status   = (values[reg] >> finger_shift) & 3;
+               /*
+                * if finger status indicates a finger is present then
+                * read the finger data and report it
+                */
+               if (finger_status == 1 || finger_status == 2) {
+                       /* Read the finger data */
+                       data_offset = data_base_addr +
+                                       ((finger * data_reg_blk_size) +
+                                       finger_registers);
+                       retval = synaptics_rmi4_i2c_block_read(pdata,
+                                               data_offset, data,
+                                               data_reg_blk_size);
+                       if (retval != data_reg_blk_size) {
+                               printk(KERN_ERR "%s:read data failed\n",
+                                                               __func__);
+                               return 0;
+                       } else {
+                               x[touch_count]  =
+                                       (data[0] << 4) | (data[2] & MASK_4BIT);
+                               y[touch_count]  =
+                                       (data[1] << 4) |
+                                       ((data[2] >> 4) & MASK_4BIT);
+                               wy[touch_count] =
+                                               (data[3] >> 4) & MASK_4BIT;
+                               wx[touch_count] =
+                                               (data[3] & MASK_4BIT);
+
+                               if (pdata->board->x_flip)
+                                       x[touch_count] =
+                                               pdata->sensor_max_x -
+                                                               x[touch_count];
+                               if (pdata->board->y_flip)
+                                       y[touch_count] =
+                                               pdata->sensor_max_y -
+                                                               y[touch_count];
+                       }
+                       /* number of active touch points */
+                       touch_count++;
+               }
+       }
+
+       /* report to input subsystem */
+       if (touch_count) {
+               for (finger = 0; finger < touch_count; finger++) {
+                       input_report_abs(pdata->input_dev, ABS_MT_TOUCH_MAJOR,
+                                               max(wx[finger] , wy[finger]));
+                       input_report_abs(pdata->input_dev, ABS_MT_POSITION_X,
+                                                               x[finger]);
+                       input_report_abs(pdata->input_dev, ABS_MT_POSITION_Y,
+                                                               y[finger]);
+                       input_mt_sync(pdata->input_dev);
+               }
+       } else
+               input_mt_sync(pdata->input_dev);
+
+       /* sync after groups of events */
+       input_sync(pdata->input_dev);
+       /* return the number of touch points */
+       return touch_count;
+}
+
+/**
+ * synaptics_rmi4_report_device() - reports the rmi4 device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @rfi: pointer to synaptics_rmi4_fn
+ *
+ * This function is used to call the report function of the rmi4 device.
+ */
+static int synaptics_rmi4_report_device(struct synaptics_rmi4_data *pdata,
+                                       struct synaptics_rmi4_fn *rfi)
+{
+       int touch = 0;
+       struct  i2c_client *client = pdata->i2c_client;
+       static int num_error_reports;
+       if (rfi->fn_number != SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM) {
+               num_error_reports++;
+               if (num_error_reports < MAX_ERROR_REPORT)
+                       dev_err(&client->dev, "%s:report not supported\n",
+                                                               __func__);
+       } else
+               touch = synpatics_rmi4_touchpad_report(pdata, rfi);
+       return touch;
+}
+/**
+ * synaptics_rmi4_sensor_report() - reports to input subsystem
+ * @pdata: pointer to synaptics_rmi4_data structure
+ *
+ * This function is used to reads in all data sources and reports
+ * them to the input subsystem.
+ */
+static int synaptics_rmi4_sensor_report(struct synaptics_rmi4_data *pdata)
+{
+       unsigned char   intr_status[4];
+       /* number of touch points - fingers or buttons */
+       int touch = 0;
+       unsigned int retval;
+       struct synaptics_rmi4_fn                *rfi;
+       struct synaptics_rmi4_device_info       *rmi;
+       struct  i2c_client *client = pdata->i2c_client;
+
+       /*
+        * Get the interrupt status from the function $01
+        * control register+1 to find which source(s) were interrupting
+        * so we can read the data from the source(s) (2D sensor, buttons..)
+        */
+       retval = synaptics_rmi4_i2c_block_read(pdata,
+                                       pdata->fn01_data_base_addr + 1,
+                                       intr_status,
+                                       pdata->number_of_interrupt_register);
+       if (retval != pdata->number_of_interrupt_register) {
+               dev_err(&client->dev,
+                               "could not read interrupt status registers\n");
+               return 0;
+       }
+       /*
+        * check each function that has data sources and if the interrupt for
+        * that triggered then call that RMI4 functions report() function to
+        * gather data and report it to the input subsystem
+        */
+       rmi = &(pdata->rmi4_mod_info);
+       list_for_each_entry(rfi, &rmi->support_fn_list, link) {
+               if (rfi->num_of_data_sources) {
+                       if (intr_status[rfi->index_to_intr_reg] &
+                                                       rfi->intr_mask)
+                               touch = synaptics_rmi4_report_device(pdata,
+                                                                       rfi);
+               }
+       }
+       /* return the number of touch points */
+       return touch;
+}
+
+/**
+ * synaptics_rmi4_irq() - thread function for rmi4 attention line
+ * @irq: irq value
+ * @data: void pointer
+ *
+ * This function is interrupt thread function. It just notifies the
+ * application layer that attention is required.
+ */
+static irqreturn_t synaptics_rmi4_irq(int irq, void *data)
+{
+       struct synaptics_rmi4_data *pdata = data;
+       int touch_count;
+       do {
+               touch_count = synaptics_rmi4_sensor_report(pdata);
+               if (touch_count)
+                       wait_event_timeout(pdata->wait, pdata->touch_stopped,
+                                                       msecs_to_jiffies(1));
+               else
+                       break;
+       } while (!pdata->touch_stopped);
+       return IRQ_HANDLED;
+}
+
+/**
+ * synpatics_rmi4_touchpad_detect() - detects the rmi4 touchpad device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @rfi: pointer to synaptics_rmi4_fn structure
+ * @fd: pointer to synaptics_rmi4_fn_desc structure
+ * @interruptcount: count the number of interrupts
+ *
+ * This function calls to detects the rmi4 touchpad device
+ */
+static int synpatics_rmi4_touchpad_detect(struct synaptics_rmi4_data *pdata,
+                                       struct synaptics_rmi4_fn *rfi,
+                                       struct synaptics_rmi4_fn_desc *fd,
+                                       unsigned int interruptcount)
+{
+       unsigned char   queries[QUERY_LEN];
+       unsigned short  intr_offset;
+       unsigned char   abs_data_size;
+       unsigned char   abs_data_blk_size;
+       unsigned char   egr_0, egr_1;
+       unsigned int    all_data_blk_size;
+       int     has_pinch, has_flick, has_tap;
+       int     has_tapandhold, has_doubletap;
+       int     has_earlytap, has_press;
+       int     has_palmdetect, has_rotate;
+       int     has_rel;
+       int     i;
+       int     retval;
+       struct  i2c_client *client = pdata->i2c_client;
+
+       rfi->fn_desc.query_base_addr    = fd->query_base_addr;
+       rfi->fn_desc.data_base_addr     = fd->data_base_addr;
+       rfi->fn_desc.intr_src_count     = fd->intr_src_count;
+       rfi->fn_desc.fn_number          = fd->fn_number;
+       rfi->fn_number                  = fd->fn_number;
+       rfi->num_of_data_sources        = fd->intr_src_count;
+       rfi->fn_desc.ctrl_base_addr     = fd->ctrl_base_addr;
+       rfi->fn_desc.cmd_base_addr      = fd->cmd_base_addr;
+
+       /*
+        * need to get number of fingers supported, data size, etc.
+        * to be used when getting data since the number of registers to
+        * read depends on the number of fingers supported and data size.
+        */
+       retval = synaptics_rmi4_i2c_block_read(pdata, fd->query_base_addr,
+                                                       queries,
+                                                       sizeof(queries));
+       if (retval != sizeof(queries)) {
+               dev_err(&client->dev, "%s:read function query registers\n",
+                                                       __func__);
+               return retval;
+       }
+       /*
+        * 2D data sources have only 3 bits for the number of fingers
+        * supported - so the encoding is a bit wierd.
+        */
+       if ((queries[1] & MASK_3BIT) <= 4)
+               /* add 1 since zero based */
+               rfi->num_of_data_points = (queries[1] & MASK_3BIT) + 1;
+       else {
+               /*
+                * a value of 5 is up to 10 fingers - 6 and 7 are reserved
+                * (shouldn't get these i int retval;n a normal 2D source).
+                */
+               if ((queries[1] & MASK_3BIT) == 5)
+                       rfi->num_of_data_points = 10;
+       }
+       /* Need to get interrupt info for handling interrupts */
+       rfi->index_to_intr_reg = (interruptcount + 7)/8;
+       if (rfi->index_to_intr_reg != 0)
+               rfi->index_to_intr_reg -= 1;
+       /*
+        * loop through interrupts for each source in fn $11
+        * and or in a bit to the interrupt mask for each.
+        */
+       intr_offset = interruptcount % 8;
+       rfi->intr_mask = 0;
+       for (i = intr_offset;
+               i < ((fd->intr_src_count & MASK_3BIT) + intr_offset); i++)
+               rfi->intr_mask |= 1 << i;
+
+       /* Size of just the absolute data for one finger */
+       abs_data_size   = queries[5] & MASK_2BIT;
+       /* One each for X and Y, one for LSB for X & Y, one for W, one for Z */
+       abs_data_blk_size = 3 + (2 * (abs_data_size == 0 ? 1 : 0));
+       rfi->size_of_data_register_block = abs_data_blk_size;
+
+       /*
+        * need to determine the size of data to read - this depends on
+        * conditions such as whether Relative data is reported and if Gesture
+        * data is reported.
+        */
+       egr_0 = queries[7];
+       egr_1 = queries[8];
+
+       /*
+        * Get info about what EGR data is supported, whether it has
+        * Relative data supported, etc.
+        */
+       has_pinch       = egr_0 & HAS_PINCH;
+       has_flick       = egr_0 & HAS_FLICK;
+       has_tap         = egr_0 & HAS_TAP;
+       has_earlytap    = egr_0 & HAS_EARLYTAP;
+       has_press       = egr_0 & HAS_PRESS;
+       has_rotate      = egr_1 & HAS_ROTATE;
+       has_rel         = queries[1] & HAS_RELEASE;
+       has_tapandhold  = egr_0 & HAS_TAPANDHOLD;
+       has_doubletap   = egr_0 & HAS_DOUBLETAP;
+       has_palmdetect  = egr_1 & HAS_PALMDETECT;
+
+       /*
+        * Size of all data including finger status, absolute data for each
+        * finger, relative data and EGR data
+        */
+       all_data_blk_size =
+               /* finger status, four fingers per register */
+               ((rfi->num_of_data_points + 3) / 4) +
+               /* absolute data, per finger times number of fingers */
+               (abs_data_blk_size * rfi->num_of_data_points) +
+               /*
+                * two relative registers (if relative is being reported)
+                */
+               2 * has_rel +
+               /*
+                * F11_2D_data8 is only present if the egr_0
+                * register is non-zero.
+                */
+               !!(egr_0) +
+               /*
+                * F11_2D_data9 is only present if either egr_0 or
+                * egr_1 registers are non-zero.
+                */
+               (egr_0 || egr_1) +
+               /*
+                * F11_2D_data10 is only present if EGR_PINCH or EGR_FLICK of
+                * egr_0 reports as 1.
+                */
+               !!(has_pinch | has_flick) +
+               /*
+                * F11_2D_data11 and F11_2D_data12 are only present if
+                * EGR_FLICK of egr_0 reports as 1.
+                */
+               2 * !!(has_flick);
+       return retval;
+}
+
+/**
+ * synpatics_rmi4_touchpad_config() - confiures the rmi4 touchpad device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ * @rfi: pointer to synaptics_rmi4_fn structure
+ *
+ * This function calls to confiures the rmi4 touchpad device
+ */
+int synpatics_rmi4_touchpad_config(struct synaptics_rmi4_data *pdata,
+                                               struct synaptics_rmi4_fn *rfi)
+{
+       /*
+        * For the data source - print info and do any
+        * source specific configuration.
+        */
+       unsigned char data[BUF_LEN];
+       int retval = 0;
+       struct  i2c_client *client = pdata->i2c_client;
+
+       /* Get and print some info about the data source... */
+       /* To Query 2D devices we need to read from the address obtained
+        * from the function descriptor stored in the RMI function info.
+        */
+       retval = synaptics_rmi4_i2c_block_read(pdata,
+                                               rfi->fn_desc.query_base_addr,
+                                               data, QUERY_LEN);
+       if (retval != QUERY_LEN)
+               dev_err(&client->dev, "%s:read query registers failed\n",
+                                                               __func__);
+       else {
+               retval = synaptics_rmi4_i2c_block_read(pdata,
+                                               rfi->fn_desc.ctrl_base_addr,
+                                               data, DATA_BUF_LEN);
+               if (retval != DATA_BUF_LEN) {
+                       dev_err(&client->dev,
+                               "%s:read control registers failed\n",
+                                                               __func__);
+                       return retval;
+               }
+               /* Store these for use later*/
+               pdata->sensor_max_x = ((data[6] & MASK_8BIT) << 0) |
+                                               ((data[7] & MASK_4BIT) << 8);
+               pdata->sensor_max_y = ((data[8] & MASK_5BIT) << 0) |
+                                               ((data[9] & MASK_4BIT) << 8);
+       }
+       return retval;
+}
+
+/**
+ * synaptics_rmi4_i2c_query_device() - query the rmi4 device
+ * @pdata: pointer to synaptics_rmi4_data structure
+ *
+ * This function is used to query the rmi4 device.
+ */
+static int synaptics_rmi4_i2c_query_device(struct synaptics_rmi4_data *pdata)
+{
+       int i;
+       int retval;
+       unsigned char std_queries[STD_QUERY_LEN];
+       unsigned char intr_count = 0;
+       int data_sources = 0;
+       unsigned int ctrl_offset;
+       struct synaptics_rmi4_fn *rfi;
+       struct synaptics_rmi4_fn_desc   rmi_fd;
+       struct synaptics_rmi4_device_info *rmi;
+       struct  i2c_client *client = pdata->i2c_client;
+
+       /*
+        * init the physical drivers RMI module
+        * info list of functions
+        */
+       INIT_LIST_HEAD(&pdata->rmi4_mod_info.support_fn_list);
+
+       /*
+        * Read the Page Descriptor Table to determine what functions
+        * are present
+        */
+       for (i = PDT_START_SCAN_LOCATION; i > PDT_END_SCAN_LOCATION;
+                                               i -= PDT_ENTRY_SIZE) {
+               retval = synaptics_rmi4_i2c_block_read(pdata, i,
+                                               (unsigned char *)&rmi_fd,
+                                               sizeof(rmi_fd));
+               if (retval != sizeof(rmi_fd)) {
+                       /* failed to read next PDT entry */
+                       dev_err(&client->dev, "%s: read error\n", __func__);
+                       return -EIO;
+               }
+               rfi = NULL;
+               if (rmi_fd.fn_number) {
+                       switch (rmi_fd.fn_number & MASK_8BIT) {
+                       case SYNAPTICS_RMI4_DEVICE_CONTROL_FUNC_NUM:
+                               pdata->fn01_query_base_addr =
+                                               rmi_fd.query_base_addr;
+                               pdata->fn01_ctrl_base_addr =
+                                               rmi_fd.ctrl_base_addr;
+                               pdata->fn01_data_base_addr =
+                                               rmi_fd.data_base_addr;
+                               break;
+                       case SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM:
+                               if (rmi_fd.intr_src_count) {
+                                       rfi = kmalloc(sizeof(*rfi),
+                                                               GFP_KERNEL);
+                                       if (!rfi) {
+                                               dev_err(&client->dev,
+                                                       "%s:kmalloc failed\n",
+                                                               __func__);
+                                                       return -ENOMEM;
+                                       }
+                                       retval = synpatics_rmi4_touchpad_detect
+                                                               (pdata, rfi,
+                                                               &rmi_fd,
+                                                               intr_count);
+                                       if (retval < 0)
+                                               return retval;
+                               }
+                               break;
+                       }
+                       /* interrupt count for next iteration */
+                       intr_count += (rmi_fd.intr_src_count & MASK_3BIT);
+                       /*
+                        * We only want to add functions to the list
+                        * that have data associated with them.
+                        */
+                       if (rfi && rmi_fd.intr_src_count) {
+                               /* link this function info to the RMI module */
+                               mutex_lock(&(pdata->fn_list_mutex));
+                               list_add_tail(&rfi->link,
+                                       &pdata->rmi4_mod_info.support_fn_list);
+                               mutex_unlock(&(pdata->fn_list_mutex));
+                       }
+               } else {
+                       /*
+                        * A zero in the function number
+                        * signals the end of the PDT
+                        */
+                       dev_dbg(&client->dev,
+                               "%s:end of PDT\n", __func__);
+                       break;
+               }
+       }
+       /*
+        * calculate the interrupt register count - used in the
+        * ISR to read the correct number of interrupt registers
+        */
+       pdata->number_of_interrupt_register = (intr_count + 7) / 8;
+       /*
+        * Function $01 will be used to query the product properties,
+        * and product ID  so we had to read the PDT above first to get
+        * the Fn $01 query address and prior to filling in the product
+        * info. NOTE: Even an unflashed device will still have FN $01.
+        */
+
+       /* Load up the standard queries and get the RMI4 module info */
+       retval = synaptics_rmi4_i2c_block_read(pdata,
+                                       pdata->fn01_query_base_addr,
+                                       std_queries,
+                                       sizeof(std_queries));
+       if (retval != sizeof(std_queries)) {
+               dev_err(&client->dev, "%s:Failed reading queries\n",
+                                                       __func__);
+                return -EIO;
+       }
+
+       /* Currently supported RMI version is 4.0 */
+       pdata->rmi4_mod_info.version_major      = 4;
+       pdata->rmi4_mod_info.version_minor      = 0;
+       /*
+        * get manufacturer id, product_props, product info,
+        * date code, tester id, serial num and product id (name)
+        */
+       pdata->rmi4_mod_info.manufacturer_id    = std_queries[0];
+       pdata->rmi4_mod_info.product_props      = std_queries[1];
+       pdata->rmi4_mod_info.product_info[0]    = std_queries[2];
+       pdata->rmi4_mod_info.product_info[1]    = std_queries[3];
+       /* year - 2001-2032 */
+       pdata->rmi4_mod_info.date_code[0]       = std_queries[4] & MASK_5BIT;
+       /* month - 1-12 */
+       pdata->rmi4_mod_info.date_code[1]       = std_queries[5] & MASK_4BIT;
+       /* day - 1-31 */
+       pdata->rmi4_mod_info.date_code[2]       = std_queries[6] & MASK_5BIT;
+       pdata->rmi4_mod_info.tester_id = ((std_queries[7] & MASK_7BIT) << 8) |
+                                               (std_queries[8] & MASK_7BIT);
+       pdata->rmi4_mod_info.serial_number =
+               ((std_queries[9] & MASK_7BIT) << 8) |
+                               (std_queries[10] & MASK_7BIT);
+       memcpy(pdata->rmi4_mod_info.product_id_string, &std_queries[11], 10);
+
+       /* Check if this is a Synaptics device - report if not. */
+       if (pdata->rmi4_mod_info.manufacturer_id != 1)
+               dev_err(&client->dev, "%s: non-Synaptics mfg id:%d\n",
+                       __func__, pdata->rmi4_mod_info.manufacturer_id);
+
+       list_for_each_entry(rfi, &pdata->rmi4_mod_info.support_fn_list, link)
+               data_sources += rfi->num_of_data_sources;
+       if (data_sources) {
+               rmi = &(pdata->rmi4_mod_info);
+               list_for_each_entry(rfi, &rmi->support_fn_list, link) {
+                       if (rfi->num_of_data_sources) {
+                               if (rfi->fn_number ==
+                                       SYNAPTICS_RMI4_TOUCHPAD_FUNC_NUM) {
+                                       retval = synpatics_rmi4_touchpad_config
+                                                               (pdata, rfi);
+                                       if (retval < 0)
+                                               return retval;
+                               } else
+                                       dev_err(&client->dev,
+                                               "%s:fn_number not supported\n",
+                                                               __func__);
+                               /*
+                                * Turn on interrupts for this
+                                * function's data sources.
+                                */
+                               ctrl_offset = pdata->fn01_ctrl_base_addr + 1 +
+                                                       rfi->index_to_intr_reg;
+                               retval = synaptics_rmi4_i2c_byte_write(pdata,
+                                                       ctrl_offset,
+                                                       rfi->intr_mask);
+                               if (retval < 0)
+                                       return retval;
+                       }
+               }
+       }
+       return 0;
+}
+
+/**
+ * synaptics_rmi4_probe() - Initialze the i2c-client touchscreen driver
+ * @i2c: i2c client structure pointer
+ * @id:i2c device id pointer
+ *
+ * This function will allocate and initialize the instance
+ * data and request the irq and set the instance data as the clients
+ * platform data then register the physical driver which will do a scan of
+ * the rmi4 Physical Device Table and enumerate any rmi4 functions that
+ * have data sources associated with them.
+ */
+static int __devinit synaptics_rmi4_probe
+       (struct i2c_client *client, const struct i2c_device_id *dev_id)
+{
+       int retval;
+       unsigned char intr_status[4];
+       struct synaptics_rmi4_data *rmi4_data;
+       const struct synaptics_rmi4_platform_data *platformdata =
+                                               client->dev.platform_data;
+
+       if (!i2c_check_functionality(client->adapter,
+                                       I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(&client->dev, "i2c smbus byte data not supported\n");
+               return -EIO;
+       }
+
+       if (!platformdata) {
+               dev_err(&client->dev, "%s: no platform data\n", __func__);
+               return -EINVAL;
+       }
+
+       /* Allocate and initialize the instance data for this client */
+       rmi4_data = kzalloc(sizeof(struct synaptics_rmi4_data) * 2,
+                                                       GFP_KERNEL);
+       if (!rmi4_data) {
+               dev_err(&client->dev, "%s: no memory allocated\n", __func__);
+               return -ENOMEM;
+       }
+
+       rmi4_data->input_dev = input_allocate_device();
+       if (rmi4_data->input_dev == NULL) {
+               dev_err(&client->dev, "%s:input device alloc failed\n",
+                                               __func__);
+               retval = -ENOMEM;
+               goto err_input;
+       }
+
+       dev_set_name(&client->dev, platformdata->name);
+
+       if (platformdata->regulator_en) {
+               rmi4_data->regulator = regulator_get(&client->dev, "v-touch");
+               if (IS_ERR(rmi4_data->regulator)) {
+                       dev_err(&client->dev, "%s:get regulator failed\n",
+                                                               __func__);
+                       retval = PTR_ERR(rmi4_data->regulator);
+                       goto err_regulator;
+               }
+               regulator_enable(rmi4_data->regulator);
+       }
+
+       init_waitqueue_head(&rmi4_data->wait);
+       /*
+        * Copy i2c_client pointer into RTID's i2c_client pointer for
+        * later use in rmi4_read, rmi4_write, etc.
+        */
+       rmi4_data->i2c_client           = client;
+       /* So we set the page correctly the first time */
+       rmi4_data->current_page         = MASK_16BIT;
+       rmi4_data->board                = platformdata;
+       rmi4_data->touch_stopped        = false;
+
+       /* init the mutexes for maintain the lists */
+       mutex_init(&(rmi4_data->fn_list_mutex));
+       mutex_init(&(rmi4_data->rmi4_page_mutex));
+
+       /*
+        * Register physical driver - this will call the detect function that
+        * will then scan the device and determine the supported
+        * rmi4 functions.
+        */
+       retval = synaptics_rmi4_i2c_query_device(rmi4_data);
+       if (retval) {
+               dev_err(&client->dev, "%s: rmi4 query device failed\n",
+                                                       __func__);
+               goto err_query_dev;
+       }
+
+       /* Store the instance data in the i2c_client */
+       i2c_set_clientdata(client, rmi4_data);
+
+       /*initialize the input device parameters */
+       rmi4_data->input_dev->name      = DRIVER_NAME;
+       rmi4_data->input_dev->phys      = "Synaptics_Clearpad";
+       rmi4_data->input_dev->id.bustype = BUS_I2C;
+       rmi4_data->input_dev->dev.parent = &client->dev;
+       input_set_drvdata(rmi4_data->input_dev, rmi4_data);
+
+       /* Initialize the function handlers for rmi4 */
+       set_bit(EV_SYN, rmi4_data->input_dev->evbit);
+       set_bit(EV_KEY, rmi4_data->input_dev->evbit);
+       set_bit(EV_ABS, rmi4_data->input_dev->evbit);
+
+       input_set_abs_params(rmi4_data->input_dev, ABS_MT_POSITION_X, 0,
+                                       rmi4_data->sensor_max_x, 0, 0);
+       input_set_abs_params(rmi4_data->input_dev, ABS_MT_POSITION_Y, 0,
+                                       rmi4_data->sensor_max_y, 0, 0);
+       input_set_abs_params(rmi4_data->input_dev, ABS_MT_TOUCH_MAJOR, 0,
+                                               MAX_TOUCH_MAJOR, 0, 0);
+
+       retval = input_register_device(rmi4_data->input_dev);
+       if (retval) {
+               dev_err(&client->dev, "%s:input register failed\n", __func__);
+               goto err_input_register;
+       }
+
+       /* Clear interrupts */
+       synaptics_rmi4_i2c_block_read(rmi4_data,
+                       rmi4_data->fn01_data_base_addr + 1, intr_status,
+                               rmi4_data->number_of_interrupt_register);
+       retval = request_threaded_irq(platformdata->irq_number, NULL,
+                                       synaptics_rmi4_irq,
+                                       platformdata->irq_type,
+                                       platformdata->name, rmi4_data);
+       if (retval) {
+               dev_err(&client->dev, "%s:Unable to get attn irq %d\n",
+                               __func__, platformdata->irq_number);
+               goto err_request_irq;
+       }
+
+       return retval;
+
+err_request_irq:
+       free_irq(platformdata->irq_number, rmi4_data);
+       input_unregister_device(rmi4_data->input_dev);
+err_input_register:
+       i2c_set_clientdata(client, NULL);
+err_query_dev:
+       if (platformdata->regulator_en) {
+               regulator_disable(rmi4_data->regulator);
+               regulator_put(rmi4_data->regulator);
+       }
+err_regulator:
+       input_free_device(rmi4_data->input_dev);
+       rmi4_data->input_dev = NULL;
+err_input:
+       kfree(rmi4_data);
+
+       return retval;
+}
+/**
+ * synaptics_rmi4_remove() - Removes the i2c-client touchscreen driver
+ * @client: i2c client structure pointer
+ *
+ * This funtion uses to remove the i2c-client
+ * touchscreen driver and returns integer.
+ */
+static int __devexit synaptics_rmi4_remove(struct i2c_client *client)
+{
+       struct synaptics_rmi4_data *rmi4_data = i2c_get_clientdata(client);
+       const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board;
+
+       rmi4_data->touch_stopped = true;
+       wake_up(&rmi4_data->wait);
+       free_irq(pdata->irq_number, rmi4_data);
+       input_unregister_device(rmi4_data->input_dev);
+       if (pdata->regulator_en) {
+               regulator_disable(rmi4_data->regulator);
+               regulator_put(rmi4_data->regulator);
+       }
+       kfree(rmi4_data);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+/**
+ * synaptics_rmi4_suspend() - suspend the touch screen controller
+ * @dev: pointer to device structure
+ *
+ * This funtion is used to suspend the
+ * touch panel controller and returns integer
+ */
+static int synaptics_rmi4_suspend(struct device *dev)
+{
+       /* Touch sleep mode */
+       int retval;
+       unsigned char intr_status;
+       struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+       const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board;
+
+       rmi4_data->touch_stopped = true;
+       disable_irq(pdata->irq_number);
+
+       retval = synaptics_rmi4_i2c_block_read(rmi4_data,
+                               rmi4_data->fn01_data_base_addr + 1,
+                               &intr_status,
+                               rmi4_data->number_of_interrupt_register);
+       if (retval < 0)
+               return retval;
+
+       retval = synaptics_rmi4_i2c_byte_write(rmi4_data,
+                                       rmi4_data->fn01_ctrl_base_addr + 1,
+                                       (intr_status & ~TOUCHPAD_CTRL_INTR));
+       if (retval < 0)
+               return retval;
+
+       if (pdata->regulator_en)
+               regulator_disable(rmi4_data->regulator);
+
+       return 0;
+}
+/**
+ * synaptics_rmi4_resume() - resume the touch screen controller
+ * @dev: pointer to device structure
+ *
+ * This funtion is used to resume the touch panel
+ * controller and returns integer.
+ */
+static int synaptics_rmi4_resume(struct device *dev)
+{
+       int retval;
+       unsigned char intr_status;
+       struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
+       const struct synaptics_rmi4_platform_data *pdata = rmi4_data->board;
+
+       if (pdata->regulator_en)
+               regulator_enable(rmi4_data->regulator);
+
+       enable_irq(pdata->irq_number);
+       rmi4_data->touch_stopped = false;
+
+       retval = synaptics_rmi4_i2c_block_read(rmi4_data,
+                               rmi4_data->fn01_data_base_addr + 1,
+                               &intr_status,
+                               rmi4_data->number_of_interrupt_register);
+       if (retval < 0)
+               return retval;
+
+       retval = synaptics_rmi4_i2c_byte_write(rmi4_data,
+                                       rmi4_data->fn01_ctrl_base_addr + 1,
+                                       (intr_status | TOUCHPAD_CTRL_INTR));
+       if (retval < 0)
+               return retval;
+
+       return 0;
+}
+
+static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = {
+       .suspend = synaptics_rmi4_suspend,
+       .resume  = synaptics_rmi4_resume,
+};
+#endif
+
+static const struct i2c_device_id synaptics_rmi4_id_table[] = {
+       { DRIVER_NAME, 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table);
+
+static struct i2c_driver synaptics_rmi4_driver = {
+       .driver = {
+               .name   =       DRIVER_NAME,
+               .owner  =       THIS_MODULE,
+#ifdef CONFIG_PM
+               .pm     =       &synaptics_rmi4_dev_pm_ops,
+#endif
+       },
+       .probe          =       synaptics_rmi4_probe,
+       .remove         =       __devexit_p(synaptics_rmi4_remove),
+       .id_table       =       synaptics_rmi4_id_table,
+};
+/**
+ * synaptics_rmi4_init() - Initialize the touchscreen driver
+ *
+ * This funtion uses to initializes the synaptics
+ * touchscreen driver and returns integer.
+ */
+static int __init synaptics_rmi4_init(void)
+{
+       return i2c_add_driver(&synaptics_rmi4_driver);
+}
+/**
+ * synaptics_rmi4_exit() - De-initialize the touchscreen driver
+ *
+ * This funtion uses to de-initialize the synaptics
+ * touchscreen driver and returns none.
+ */
+static void __exit synaptics_rmi4_exit(void)
+{
+       i2c_del_driver(&synaptics_rmi4_driver);
+}
+
+
+module_init(synaptics_rmi4_init);
+module_exit(synaptics_rmi4_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("naveen.gaddipati@stericsson.com, js.ha@stericsson.com");
+MODULE_DESCRIPTION("synaptics rmi4 i2c touch Driver");
+MODULE_ALIAS("i2c:synaptics_rmi4_ts");
diff --git a/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.h b/drivers/staging/ste_rmi4/synaptics_i2c_rmi4.h
new file mode 100644 (file)
index 0000000..820ae27
--- /dev/null
@@ -0,0 +1,50 @@
+/**
+ *
+ * Synaptics Register Mapped Interface (RMI4) I2C Physical Layer Driver.
+ * Copyright (c) 2007-2010, Synaptics Incorporated
+ *
+ * Author: Js HA <js.ha@stericsson.com> for ST-Ericsson
+ * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
+ * Copyright 2010 (c) ST-Ericsson AB
+ */
+/*
+ * This file is licensed under the GPL2 license.
+ *
+ *#############################################################################
+ * GPL
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ *#############################################################################
+ */
+
+#ifndef _SYNAPTICS_RMI4_H_INCLUDED_
+#define _SYNAPTICS_RMI4_H_INCLUDED_
+
+/**
+ * struct synaptics_rmi4_platform_data - contains the rmi4 platform data
+ * @irq_number: irq number
+ * @irq_type: irq type
+ * @x flip: x flip flag
+ * @y flip: y flip flag
+ * @regulator_en: regulator enable flag
+ *
+ * This structure gives platform data for rmi4.
+ */
+struct synaptics_rmi4_platform_data {
+       const char *name;
+       int irq_number;
+       int irq_type;
+       bool x_flip;
+       bool y_flip;
+       bool regulator_en;
+};
+
+#endif
index 8de21aac1bff3e0f9e11bd002dd42f33050e821f..a49053bd7c65e1977fcbfb8ef3951c0cad290ae3 100644 (file)
@@ -1092,7 +1092,7 @@ CARDbChannelSwitch (
         pDevice->sMgmtObj.uCurrChannel = byNewChannel;
         bResult = CARDbSetMediaChannel(pDevice, byNewChannel);
 
-        return(bResult);
+       return bResult;
     }
     pDevice->byChannelSwitchCount = byCount;
     pDevice->byNewChannel = byNewChannel;
index 1f9d29636803fcc4ec1f1e10dffe742d7c0e4196..f4fb0c6e4eacc83a6365475197ef175916ff300b 100644 (file)
@@ -1608,8 +1608,8 @@ void RXvMngWorkItem(void *Context)
         }
     }
 
-    pDevice->bIsRxMngWorkItemQueued = FALSE;
-    spin_unlock_irq(&pDevice->lock);
+       pDevice->bIsRxMngWorkItemQueued = FALSE;
+       spin_unlock_irq(&pDevice->lock);
 
 }
 
index bbdc127a987d0184bd557d02f1a5cbfcbd4b8382..8f18578a59038b3c786acd19325c7d80e3e6b26d 100644 (file)
@@ -68,8 +68,7 @@
 /*---------------------  Static Classes  ----------------------------*/
 
 /*---------------------  Static Variables  --------------------------*/
-//static int          msglevel                =MSG_LEVEL_DEBUG;
-static int          msglevel                =MSG_LEVEL_INFO;
+static int          msglevel                = MSG_LEVEL_INFO;
 
 /*---------------------  Static Functions  --------------------------*/
 
index a6bd533f9577dc405a680535194ead57d617dd02..0715636cb9cb1f5cbe1fe8a07c5bf1bf9af7b195 100644 (file)
@@ -214,13 +214,14 @@ void TKIPvMixKey(
     /* Phase 1, step 2 */
     for (i=0; i<8; i++) {
         j = 2*(i & 1);
-        p1k[0] = (p1k[0] + tkip_sbox( (p1k[4] ^ ((256*pbyTKey[1+j]) + pbyTKey[j])) % 65536 )) % 65536;
-        p1k[1] = (p1k[1] + tkip_sbox( (p1k[0] ^ ((256*pbyTKey[5+j]) + pbyTKey[4+j])) % 65536 )) % 65536;
-        p1k[2] = (p1k[2] + tkip_sbox( (p1k[1] ^ ((256*pbyTKey[9+j]) + pbyTKey[8+j])) % 65536 )) % 65536;
-        p1k[3] = (p1k[3] + tkip_sbox( (p1k[2] ^ ((256*pbyTKey[13+j]) + pbyTKey[12+j])) % 65536 )) % 65536;
-        p1k[4] = (p1k[4] + tkip_sbox( (p1k[3] ^ (((256*pbyTKey[1+j]) + pbyTKey[j]))) % 65536 )) % 65536;
+        p1k[0] = (p1k[0] + tkip_sbox((p1k[4] ^ ((256*pbyTKey[1+j]) + pbyTKey[j])) % 65536)) % 65536;
+        p1k[1] = (p1k[1] + tkip_sbox((p1k[0] ^ ((256*pbyTKey[5+j]) + pbyTKey[4+j])) % 65536)) % 65536;
+        p1k[2] = (p1k[2] + tkip_sbox((p1k[1] ^ ((256*pbyTKey[9+j]) + pbyTKey[8+j])) % 65536)) % 65536;
+        p1k[3] = (p1k[3] + tkip_sbox((p1k[2] ^ ((256*pbyTKey[13+j]) + pbyTKey[12+j])) % 65536)) % 65536;
+        p1k[4] = (p1k[4] + tkip_sbox((p1k[3] ^ (((256*pbyTKey[1+j]) + pbyTKey[j]))) % 65536)) % 65536;
         p1k[4] = (p1k[4] + i) % 65536;
     }
     /* Phase 2, Step 1 */
     ppk0 = p1k[0];
     ppk1 = p1k[1];
@@ -230,19 +231,19 @@ void TKIPvMixKey(
     ppk5 = (p1k[4] + tsc2) % 65536;
 
     /* Phase2, Step 2 */
-    ppk0 = ppk0 + tkip_sbox( (ppk5 ^ ((256*pbyTKey[1]) + pbyTKey[0])) % 65536);
-    ppk1 = ppk1 + tkip_sbox( (ppk0 ^ ((256*pbyTKey[3]) + pbyTKey[2])) % 65536);
-    ppk2 = ppk2 + tkip_sbox( (ppk1 ^ ((256*pbyTKey[5]) + pbyTKey[4])) % 65536);
-    ppk3 = ppk3 + tkip_sbox( (ppk2 ^ ((256*pbyTKey[7]) + pbyTKey[6])) % 65536);
-    ppk4 = ppk4 + tkip_sbox( (ppk3 ^ ((256*pbyTKey[9]) + pbyTKey[8])) % 65536);
-    ppk5 = ppk5 + tkip_sbox( (ppk4 ^ ((256*pbyTKey[11]) + pbyTKey[10])) % 65536);
-
-    ppk0 = ppk0 + rotr1(ppk5 ^ ((256*pbyTKey[13]) + pbyTKey[12]));
-    ppk1 = ppk1 + rotr1(ppk0 ^ ((256*pbyTKey[15]) + pbyTKey[14]));
-    ppk2 = ppk2 + rotr1(ppk1);
-    ppk3 = ppk3 + rotr1(ppk2);
-    ppk4 = ppk4 + rotr1(ppk3);
-    ppk5 = ppk5 + rotr1(ppk4);
+       ppk0 = ppk0 + tkip_sbox((ppk5 ^ ((256*pbyTKey[1]) + pbyTKey[0])) % 65536);
+       ppk1 = ppk1 + tkip_sbox((ppk0 ^ ((256*pbyTKey[3]) + pbyTKey[2])) % 65536);
+       ppk2 = ppk2 + tkip_sbox((ppk1 ^ ((256*pbyTKey[5]) + pbyTKey[4])) % 65536);
+       ppk3 = ppk3 + tkip_sbox((ppk2 ^ ((256*pbyTKey[7]) + pbyTKey[6])) % 65536);
+       ppk4 = ppk4 + tkip_sbox((ppk3 ^ ((256*pbyTKey[9]) + pbyTKey[8])) % 65536);
+       ppk5 = ppk5 + tkip_sbox((ppk4 ^ ((256*pbyTKey[11]) + pbyTKey[10])) % 65536);
+
+       ppk0 = ppk0 + rotr1(ppk5 ^ ((256*pbyTKey[13]) + pbyTKey[12]));
+       ppk1 = ppk1 + rotr1(ppk0 ^ ((256*pbyTKey[15]) + pbyTKey[14]));
+       ppk2 = ppk2 + rotr1(ppk1);
+       ppk3 = ppk3 + rotr1(ppk2);
+       ppk4 = ppk4 + rotr1(ppk3);
+       ppk5 = ppk5 + rotr1(ppk4);
 
     /* Phase 2, Step 3 */
     pbyRC4Key[0] = (tsc2 >> 8) % 256;
index 2b87a0007319514fab692a40bb420dacd5ab3098..d7b3aca5ddebaa71ca7ac169edefc78ef1b7e5b7 100644 (file)
@@ -4,7 +4,7 @@
 #include <linux/wireless.h>
 #include <linux/types.h>
 
-#include "wbhal_s.h"
+#include "wbhal.h"
 #include "mto.h"
 
 #include "mac_structures.h"
index 9217762b18141460f568c29676d41b5c5f3539e4..90f2cc019d3b73a351e97ee8e38d058f6969881f 100644 (file)
@@ -2,8 +2,9 @@
 #include "mlmetxrx_f.h"
 #include "mto.h"
 #include "sysdef.h"
-#include "wbhal_f.h"
+#include "wbhal.h"
 #include "wblinux_f.h"
+#include "wb35tx_f.h"
 
 unsigned char
 Mds_initial(struct wbsoft_priv *adapter)
@@ -17,11 +18,6 @@ Mds_initial(struct wbsoft_priv *adapter)
        return hal_get_tx_buffer(&adapter->sHwData, &pMds->pTxBuffer);
 }
 
-void
-Mds_Destroy(struct wbsoft_priv *adapter)
-{
-}
-
 static void Mds_DurationSet(struct wbsoft_priv *adapter,  struct wb35_descriptor *pDes,  u8 *buffer)
 {
        struct T00_descriptor *pT00;
index 7f68deae6d04f83f039764e7662e87344f875ae8..ce8be079e957cd0cc5e6d3e975a7a0f9c1a8cf86 100644 (file)
@@ -1,11 +1,10 @@
 #ifndef __WINBOND_MDS_F_H
 #define __WINBOND_MDS_F_H
 
-#include "wbhal_s.h"
+#include "wbhal.h"
 #include "core.h"
 
 unsigned char Mds_initial(struct wbsoft_priv *adapter);
-void Mds_Destroy(struct wbsoft_priv *adapter);
 void Mds_Tx(struct wbsoft_priv *adapter);
 void Mds_SendComplete(struct wbsoft_priv *adapter, struct T02_descriptor *pt02);
 void Mds_MpduProcess(struct wbsoft_priv *adapter, struct wb35_descriptor *prxdes);
index 9cd212783d6168514a235691c80aa6b839f17482..1faebceceff7b2d4bf3a2a6041f308f45acb6321 100644 (file)
@@ -19,7 +19,9 @@
 
 #include "sysdef.h"
 #include "sme_api.h"
-#include "wbhal_f.h"
+#include "wbhal.h"
+#include "wb35reg_f.h"
+#include "core.h"
 
 /* Declare SQ3 to rate and fragmentation threshold table */
 /* Declare fragmentation thresholds table */
index 2b375ba3812adc25a4f45a5f48fa156de249f8ee..0658b09c78531e45e2922d7c53469cccead72200 100644 (file)
@@ -12,7 +12,9 @@
 /****************** INCLUDE FILES SECTION ***********************************/
 #include "sysdef.h"
 #include "phy_calibration.h"
-#include "wbhal_f.h"
+#include "wbhal.h"
+#include "wb35reg_f.h"
+#include "core.h"
 
 
 /****************** DEBUG CONSTANT AND MACRO SECTION ************************/
index 30320314883968f4f6f0bd8185d78e8a53db3c9d..84f6e840a47a9121b2fb155e3d010fb61246e068 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __WINBOND_PHY_CALIBRATION_H
 #define __WINBOND_PHY_CALIBRATION_H
 
-#include "wbhal_f.h"
+#include "wbhal.h"
 
 #define REG_AGC_CTRL1          0x1000
 #define REG_AGC_CTRL2          0x1004
index 990f9d4bdbbd992ffac811632a2daaf7aa1241f2..439d213fe951271894f5d0ed9f91020a72bc7880 100644 (file)
@@ -1,5 +1,7 @@
 #include "sysdef.h"
-#include "wbhal_f.h"
+#include "wbhal.h"
+#include "wb35reg_f.h"
+#include "core.h"
 
 /*
  * ====================================================
index bf23c10841999039b9c94cbac9e7cebdfd21eb72..95dc98096845e07e30b4ea6ba9e447c0f1712d94 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __WINBOND_WB35REG_F_H
 #define __WINBOND_WB35REG_F_H
 
-#include "wbhal_s.h"
+#include "wbhal.h"
 
 /*
  * ====================================
index 4eff009444b870f34b42827aa290cf117aca160a..9d5993bfc1f404c185c9ddb8c8fc27e76c7fe4c4 100644 (file)
@@ -5,6 +5,8 @@
 #include <linux/types.h>
 #include <asm/atomic.h>
 
+struct hw_data;
+
 /* =========================================================================
  *
  *                     HAL setting function
@@ -168,4 +170,76 @@ struct wb35_reg {
        u32     SQ3_filter[MAX_SQ3_FILTER_SIZE];
        u32     SQ3_index;
 };
+
+/* =====================================================================
+ * Function declaration
+ * =====================================================================
+ */
+void hal_remove_mapping_key(struct hw_data *hw_data, u8 *mac_addr);
+void hal_remove_default_key(struct hw_data *hw_data, u32 index);
+unsigned char hal_set_mapping_key(struct hw_data *adapter, u8 *mac_addr,
+                                 u8 null_key, u8 wep_on, u8 *tx_tsc,
+                                 u8 *rx_tsc, u8 key_type, u8 key_len,
+                                 u8 *key_data);
+unsigned char hal_set_default_key(struct hw_data *adapter, u8 index,
+                                 u8 null_key, u8 wep_on, u8 *tx_tsc,
+                                 u8 *rx_tsc, u8 key_type, u8 key_len,
+                                 u8 *key_data);
+void hal_clear_all_default_key(struct hw_data *hw_data);
+void hal_clear_all_group_key(struct hw_data *hw_data);
+void hal_clear_all_mapping_key(struct hw_data *hw_data);
+void hal_clear_all_key(struct hw_data *hw_data);
+void hal_set_power_save_mode(struct hw_data *hw_data, unsigned char power_save,
+                            unsigned char wakeup, unsigned char dtim);
+void hal_get_power_save_mode(struct hw_data *hw_data, u8 *in_pwr_save);
+void hal_set_slot_time(struct hw_data *hw_data, u8 type);
+
+#define hal_set_atim_window(_A, _ATM)
+
+void hal_start_bss(struct hw_data *hw_data, u8 mac_op_mode);
+
+/* 0:BSS STA 1:IBSS STA */
+void hal_join_request(struct hw_data *hw_data, u8 bss_type);
+
+void hal_stop_sync_bss(struct hw_data *hw_data);
+void hal_resume_sync_bss(struct hw_data *hw_data);
+void hal_set_aid(struct hw_data *hw_data, u16 aid);
+void hal_set_bssid(struct hw_data *hw_data, u8 *bssid);
+void hal_get_bssid(struct hw_data *hw_data, u8 *bssid);
+void hal_set_listen_interval(struct hw_data *hw_data, u16 listen_interval);
+void hal_set_cap_info(struct hw_data *hw_data, u16 capability_info);
+void hal_set_ssid(struct hw_data *hw_data, u8 *ssid, u8 ssid_len);
+void hal_start_tx0(struct hw_data *hw_data);
+
+#define hal_get_cwmin(_A)      ((_A)->cwmin)
+
+void hal_set_cwmax(struct hw_data *hw_data, u16 cwin_max);
+
+#define hal_get_cwmax(_A)      ((_A)->cwmax)
+
+void hal_set_rsn_wpa(struct hw_data *hw_data, u32 *rsn_ie_bitmap,
+                    u32 *rsn_oui_type , unsigned char desired_auth_mode);
+void hal_set_connect_info(struct hw_data *hw_data, unsigned char bo_connect);
+u8 hal_get_est_sq3(struct hw_data *hw_data, u8 count);
+void hal_descriptor_indicate(struct hw_data *hw_data,
+                            struct wb35_descriptor *des);
+u8 hal_get_antenna_number(struct hw_data *hw_data);
+u32 hal_get_bss_pk_cnt(struct hw_data *hw_data);
+
+#define hal_get_region_from_EEPROM(_A) ((_A)->reg.EEPROMRegion)
+#define hal_get_tx_buffer(_A, _B)      Wb35Tx_get_tx_buffer(_A, _B)
+#define hal_software_set(_A)           (_A->SoftwareSet)
+#define hal_driver_init_OK(_A)         (_A->IsInitOK)
+#define hal_rssi_boundary_high(_A)     (_A->RSSI_high)
+#define hal_rssi_boundary_low(_A)      (_A->RSSI_low)
+#define hal_scan_interval(_A)          (_A->Scan_Interval)
+
+#define PHY_DEBUG(msg, args...)
+
+/* return 100ms count */
+#define hal_get_time_count(_P)         (_P->time_count / 10)
+#define hal_detect_error(_P)           (_P->WbUsb.DetectCount)
+
+#define hal_ibss_disconnect(_A)                (hal_stop_sync_bss(_A))
+
 #endif
index 448514aada44e3c0eb5c3a9f4ce6aa32d772af57..5af271f2de9c05a1d9a0e9f20106ed2306c76353 100644 (file)
@@ -174,7 +174,7 @@ static void Wb35Rx_Complete(struct urb *urb)
        /* The IRP is completed */
        pWb35Rx->EP3vm_state = VM_COMPLETED;
 
-       if (pHwData->SurpriseRemove || pHwData->HwStop) /* Must be here, or RxBufferId is invalid */
+       if (pHwData->SurpriseRemove) /* Must be here, or RxBufferId is invalid */
                goto error;
 
        if (pWb35Rx->rx_halt)
@@ -239,7 +239,7 @@ static void Wb35Rx(struct ieee80211_hw *hw)
        u32                     RxBufferId;
 
        /* Issuing URB */
-       if (pHwData->SurpriseRemove || pHwData->HwStop)
+       if (pHwData->SurpriseRemove)
                goto error;
 
        if (pWb35Rx->rx_halt)
index 98acce517d9019af73c5ebcd075c45c7132daaa2..1fdf65ea6041962f7a964abe8c49962db968aef6 100644 (file)
@@ -2,7 +2,7 @@
 #define __WINBOND_WB35RX_F_H
 
 #include <net/mac80211.h>
-#include "wbhal_s.h"
+#include "wbhal.h"
 
 //====================================
 // Interface function declare
index 2a9d0555767854209fbcc351abd6da20f56d8433..fd52554e46f84f548e26cc11fe3de38b714f0b1d 100644 (file)
@@ -41,7 +41,7 @@ static void Wb35Tx_complete(struct urb * pUrb)
        pWb35Tx->TxSendIndex++;
        pWb35Tx->TxSendIndex %= MAX_USB_TX_BUFFER_NUMBER;
 
-       if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove
+       if (pHwData->SurpriseRemove) // Let WbWlanHalt to handle surprise remove
                goto error;
 
        if (pWb35Tx->tx_halt)
@@ -74,7 +74,7 @@ static void Wb35Tx(struct wbsoft_priv *adapter)
        u32             SendIndex;
 
 
-       if (pHwData->SurpriseRemove || pHwData->HwStop)
+       if (pHwData->SurpriseRemove)
                goto cleanup;
 
        if (pWb35Tx->tx_halt)
@@ -222,7 +222,7 @@ static void Wb35Tx_EP2VM_complete(struct urb * pUrb)
        pWb35Tx->EP2VM_status = pUrb->status;
 
        // For Linux 2.4. Interrupt will always trigger
-       if (pHwData->SurpriseRemove || pHwData->HwStop) // Let WbWlanHalt to handle surprise remove
+       if (pHwData->SurpriseRemove) // Let WbWlanHalt to handle surprise remove
                goto error;
 
        if (pWb35Tx->tx_halt)
@@ -263,7 +263,7 @@ static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter)
        u32 *   pltmp = (u32 *)pWb35Tx->EP2_buf;
        int             retv;
 
-       if (pHwData->SurpriseRemove || pHwData->HwStop)
+       if (pHwData->SurpriseRemove)
                goto error;
 
        if (pWb35Tx->tx_halt)
index 1d3b515f83bc09ad6d66fba9ba58c5ace4b4c339..018fd35e815dbca9a2496b39b8e3097a82f20da3 100644 (file)
@@ -2,7 +2,6 @@
 #define __WINBOND_WB35TX_F_H
 
 #include "core.h"
-#include "wbhal_f.h"
 
 /*
  * ====================================
diff --git a/drivers/staging/winbond/wbhal.h b/drivers/staging/winbond/wbhal.h
new file mode 100644 (file)
index 0000000..dcf3b21
--- /dev/null
@@ -0,0 +1,514 @@
+#ifndef __WINBOND_WBHAL_S_H
+#define __WINBOND_WBHAL_S_H
+
+#include <linux/types.h>
+#include <linux/if_ether.h> /* for ETH_ALEN */
+
+#define HAL_LED_SET_MASK       0x001c
+#define HAL_LED_SET_SHIFT      2
+
+/* supported RF type */
+#define RF_MAXIM_2825          0
+#define RF_MAXIM_2827          1
+#define RF_MAXIM_2828          2
+#define RF_MAXIM_2829          3
+#define RF_MAXIM_V1            15
+#define RF_AIROHA_2230         16
+#define RF_AIROHA_7230         17
+#define RF_AIROHA_2230S                18
+#define RF_WB_242              33
+#define RF_WB_242_1            34
+#define RF_DECIDE_BY_INF       255
+
+/*
+ * ----------------------------------------------------------------
+ * The follow define connect to upper layer
+ *     User must modify for connection between HAL and upper layer
+ * ----------------------------------------------------------------
+ */
+
+/*
+ * ==============================
+ * Common define
+ * ==============================
+ */
+/* Bit 5 */
+#define HAL_USB_MODE_BURST(_H)                 (_H->SoftwareSet & 0x20)
+
+/* Scan interval */
+#define SCAN_MAX_CHNL_TIME                     (50)
+
+/* For TxL2 Frame typr recognise */
+#define FRAME_TYPE_802_3_DATA                  0
+#define FRAME_TYPE_802_11_MANAGEMENT           1
+#define FRAME_TYPE_802_11_MANAGEMENT_CHALLENGE 2
+#define FRAME_TYPE_802_11_CONTROL              3
+#define FRAME_TYPE_802_11_DATA                 4
+#define FRAME_TYPE_PROMISCUOUS                 5
+
+/* The follow definition is used for convert the frame------------ */
+#define DOT_11_SEQUENCE_OFFSET                 22 /* Sequence control offset */
+#define DOT_3_TYPE_OFFSET                      12
+#define DOT_11_MAC_HEADER_SIZE                 24
+#define DOT_11_SNAP_SIZE                       6
+#define DOT_11_TYPE_OFFSET                     30 /* The start offset of 802.11 Frame. Type encapsulation. */
+#define DEFAULT_SIFSTIME                       10
+#define DEFAULT_FRAGMENT_THRESHOLD             2346 /* No fragment */
+#define DEFAULT_MSDU_LIFE_TIME                 0xffff
+
+#define LONG_PREAMBLE_PLUS_PLCPHEADER_TIME             (144 + 48)
+#define SHORT_PREAMBLE_PLUS_PLCPHEADER_TIME            (72 + 24)
+#define PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION      (16 + 4 + 6)
+#define Tsym                                           4
+
+/*  Frame Type of Bits (2, 3)----------------------------------- */
+#define MAC_TYPE_MANAGEMENT                    0x00
+#define MAC_TYPE_CONTROL                       0x04
+#define MAC_TYPE_DATA                          0x08
+#define MASK_FRAGMENT_NUMBER                   0x000F
+#define SEQUENCE_NUMBER_SHIFT                  4
+
+#define  HAL_WOL_TYPE_WAKEUP_FRAME             0x01
+#define  HAL_WOL_TYPE_MAGIC_PACKET             0x02
+
+#define HAL_KEYTYPE_WEP40                      0
+#define HAL_KEYTYPE_WEP104                     1
+#define HAL_KEYTYPE_TKIP                       2 /* 128 bit key */
+#define HAL_KEYTYPE_AES_CCMP                   3 /* 128 bit key */
+
+/* For VM state */
+enum {
+       VM_STOP = 0,
+       VM_RUNNING,
+       VM_COMPLETED
+};
+
+/*
+ * ================================
+ * Normal Key table format
+ * ================================
+ */
+
+/* The order of KEY index is MAPPING_KEY_START_INDEX > GROUP_KEY_START_INDEX */
+#define MAX_KEY_TABLE                  24 /* 24 entry for storing key data */
+#define GROUP_KEY_START_INDEX          4
+#define MAPPING_KEY_START_INDEX                8
+
+/*
+ * =========================================
+ * Descriptor
+ * =========================================
+ */
+#define MAX_DESCRIPTOR_BUFFER_INDEX    8 /* Have to multiple of 2 */
+#define FLAG_ERROR_TX_MASK             0x000000bf
+#define FLAG_ERROR_RX_MASK             0x0000083f
+
+#define FLAG_BAND_RX_MASK              0x10000000 /* Bit 28 */
+
+struct R00_descriptor {
+       union {
+               u32     value;
+#ifdef _BIG_ENDIAN_
+               struct {
+                       u32     R00_packet_or_buffer_status:1;
+                       u32     R00_packet_in_fifo:1;
+                       u32     R00_RESERVED:2;
+                       u32     R00_receive_byte_count:12;
+                       u32     R00_receive_time_index:16;
+               };
+#else
+               struct {
+                       u32     R00_receive_time_index:16;
+                       u32     R00_receive_byte_count:12;
+                       u32     R00_RESERVED:2;
+                       u32     R00_packet_in_fifo:1;
+                       u32     R00_packet_or_buffer_status:1;
+               };
+#endif
+       };
+};
+
+struct T00_descriptor {
+       union {
+               u32     value;
+#ifdef _BIG_ENDIAN_
+               struct {
+                       u32     T00_first_mpdu:1; /* for hardware use */
+                       u32     T00_last_mpdu:1; /* for hardware use */
+                       u32     T00_IsLastMpdu:1;/* 0:not 1:Yes for software used */
+                       u32     T00_IgnoreResult:1;/* The same mechanism with T00 setting. */
+                       u32     T00_RESERVED_ID:2;/* 3 bit ID reserved */
+                       u32     T00_tx_packet_id:4;
+                       u32     T00_RESERVED:4;
+                       u32     T00_header_length:6;
+                       u32     T00_frame_length:12;
+               };
+#else
+               struct {
+                       u32     T00_frame_length:12;
+                       u32     T00_header_length:6;
+                       u32     T00_RESERVED:4;
+                       u32     T00_tx_packet_id:4;
+                       u32     T00_RESERVED_ID:2; /* 3 bit ID reserved */
+                       u32     T00_IgnoreResult:1; /* The same mechanism with T00 setting. */
+                       u32     T00_IsLastMpdu:1; /* 0:not 1:Yes for software used */
+                       u32     T00_last_mpdu:1; /* for hardware use */
+                       u32     T00_first_mpdu:1; /* for hardware use */
+               };
+#endif
+       };
+};
+
+struct R01_descriptor {
+       union {
+               u32     value;
+#ifdef _BIG_ENDIAN_
+               struct {
+                       u32     R01_RESERVED:3;
+                       u32     R01_mod_type:1;
+                       u32     R01_pre_type:1;
+                       u32     R01_data_rate:3;
+                       u32     R01_AGC_state:8;
+                       u32     R01_LNA_state:2;
+                       u32     R01_decryption_method:2;
+                       u32     R01_mic_error:1;
+                       u32     R01_replay:1;
+                       u32     R01_broadcast_frame:1;
+                       u32     R01_multicast_frame:1;
+                       u32     R01_directed_frame:1;
+                       u32     R01_receive_frame_antenna_selection:1;
+                       u32     R01_frame_receive_during_atim_window:1;
+                       u32     R01_protocol_version_error:1;
+                       u32     R01_authentication_frame_icv_error:1;
+                       u32     R01_null_key_to_authentication_frame:1;
+                       u32     R01_icv_error:1;
+                       u32     R01_crc_error:1;
+               };
+#else
+               struct {
+                       u32     R01_crc_error:1;
+                       u32     R01_icv_error:1;
+                       u32     R01_null_key_to_authentication_frame:1;
+                       u32     R01_authentication_frame_icv_error:1;
+                       u32     R01_protocol_version_error:1;
+                       u32     R01_frame_receive_during_atim_window:1;
+                       u32     R01_receive_frame_antenna_selection:1;
+                       u32     R01_directed_frame:1;
+                       u32     R01_multicast_frame:1;
+                       u32     R01_broadcast_frame:1;
+                       u32     R01_replay:1;
+                       u32     R01_mic_error:1;
+                       u32     R01_decryption_method:2;
+                       u32     R01_LNA_state:2;
+                       u32     R01_AGC_state:8;
+                       u32     R01_data_rate:3;
+                       u32     R01_pre_type:1;
+                       u32     R01_mod_type:1;
+                       u32     R01_RESERVED:3;
+               };
+#endif
+       };
+};
+
+struct T01_descriptor {
+       union {
+               u32     value;
+#ifdef _BIG_ENDIAN_
+               struct {
+                       u32     T01_rts_cts_duration:16;
+                       u32     T01_fall_back_rate:3;
+                       u32     T01_add_rts:1;
+                       u32     T01_add_cts:1;
+                       u32     T01_modulation_type:1;
+                       u32     T01_plcp_header_length:1;
+                       u32     T01_transmit_rate:3;
+                       u32     T01_wep_id:2;
+                       u32     T01_add_challenge_text:1;
+                       u32     T01_inhibit_crc:1;
+                       u32     T01_loop_back_wep_mode:1;
+                       u32     T01_retry_abort_ebable:1;
+               };
+#else
+               struct {
+                       u32     T01_retry_abort_ebable:1;
+                       u32     T01_loop_back_wep_mode:1;
+                       u32     T01_inhibit_crc:1;
+                       u32     T01_add_challenge_text:1;
+                       u32     T01_wep_id:2;
+                       u32     T01_transmit_rate:3;
+                       u32     T01_plcp_header_length:1;
+                       u32     T01_modulation_type:1;
+                       u32     T01_add_cts:1;
+                       u32     T01_add_rts:1;
+                       u32     T01_fall_back_rate:3;
+                       u32     T01_rts_cts_duration:16;
+               };
+#endif
+       };
+};
+
+struct T02_descriptor {
+       union {
+               u32     value;
+#ifdef _BIG_ENDIAN_
+               struct {
+                       u32     T02_IsLastMpdu:1; /* The same mechanism with T00 setting */
+                       u32     T02_IgnoreResult:1; /* The same mechanism with T00 setting. */
+                       u32     T02_RESERVED_ID:2; /* The same mechanism with T00 setting */
+                       u32     T02_Tx_PktID:4;
+                       u32     T02_MPDU_Cnt:4;
+                       u32     T02_RTS_Cnt:4;
+                       u32     T02_RESERVED:7;
+                       u32     T02_transmit_complete:1;
+                       u32     T02_transmit_abort_due_to_TBTT:1;
+                       u32     T02_effective_transmission_rate:1;
+                       u32     T02_transmit_without_encryption_due_to_wep_on_false:1;
+                       u32     T02_discard_due_to_null_wep_key:1;
+                       u32     T02_RESERVED_1:1;
+                       u32     T02_out_of_MaxTxMSDULiftTime:1;
+                       u32     T02_transmit_abort:1;
+                       u32     T02_transmit_fail:1;
+               };
+#else
+               struct {
+                       u32     T02_transmit_fail:1;
+                       u32     T02_transmit_abort:1;
+                       u32     T02_out_of_MaxTxMSDULiftTime:1;
+                       u32     T02_RESERVED_1:1;
+                       u32     T02_discard_due_to_null_wep_key:1;
+                       u32     T02_transmit_without_encryption_due_to_wep_on_false:1;
+                       u32     T02_effective_transmission_rate:1;
+                       u32     T02_transmit_abort_due_to_TBTT:1;
+                       u32     T02_transmit_complete:1;
+                       u32     T02_RESERVED:7;
+                       u32     T02_RTS_Cnt:4;
+                       u32     T02_MPDU_Cnt:4;
+                       u32     T02_Tx_PktID:4;
+                       u32     T02_RESERVED_ID:2; /* The same mechanism with T00 setting */
+                       u32     T02_IgnoreResult:1; /* The same mechanism with T00 setting. */
+                       u32     T02_IsLastMpdu:1; /* The same mechanism with T00 setting */
+               };
+#endif
+       };
+};
+
+struct wb35_descriptor { /* Skip length = 8 DWORD */
+       /* ID for descriptor ---, The field doesn't be cleard in the operation of Descriptor definition */
+       u8      Descriptor_ID;
+       /* ----------------------The above region doesn't be cleared by DESCRIPTOR_RESET------ */
+       u8      RESERVED[3];
+
+       u16     FragmentThreshold;
+       u8      InternalUsed; /* Only can be used by operation of descriptor definition */
+       u8      Type; /* 0: 802.3 1:802.11 data frame 2:802.11 management frame */
+
+       u8      PreambleMode;/* 0: short 1:long */
+       u8      TxRate;
+       u8      FragmentCount;
+       u8      EapFix; /* For speed up key install */
+
+       /* For R00 and T00 ------------------------------ */
+       union {
+               struct R00_descriptor   R00;
+               struct T00_descriptor   T00;
+       };
+
+       /* For R01 and T01 ------------------------------ */
+       union {
+               struct R01_descriptor   R01;
+               struct T01_descriptor   T01;
+       };
+
+       /* For R02 and T02 ------------------------------ */
+       union {
+               u32             R02;
+               struct T02_descriptor   T02;
+       };
+
+       /* For R03 and T03 ------------------------------ */
+       /* For software used */
+       union {
+               u32     R03;
+               u32     T03;
+               struct {
+                       u8      buffer_number;
+                       u8      buffer_start_index;
+                       u16     buffer_total_size;
+               };
+       };
+
+       /* For storing the buffer */
+       u16     buffer_size[MAX_DESCRIPTOR_BUFFER_INDEX];
+       void    *buffer_address[MAX_DESCRIPTOR_BUFFER_INDEX];
+};
+
+#define MAX_TXVGA_EEPROM               9       /* How many word(u16) of EEPROM will be used for TxVGA */
+#define MAX_RF_PARAMETER               32
+
+struct txvga_for_50 {
+       u8      ChanNo;
+       u8      TxVgaValue;
+};
+
+/*
+ * ==============================================
+ * Device related include
+ * ==============================================
+ */
+
+#include "wbusb_s.h"
+#include "wb35reg_s.h"
+#include "wb35tx_s.h"
+#include "wb35rx_s.h"
+
+/* For Hal using ============================================ */
+struct hw_data {
+       /* For compatible with 33 */
+       u32     revision;
+       u32     BB3c_cal; /* The value for Tx calibration comes from EEPROM */
+       u32     BB54_cal; /* The value for Rx calibration comes from EEPROM */
+
+       /* For surprise remove */
+       u32     SurpriseRemove; /* 0: Normal 1: Surprise remove */
+       u8      IsKeyPreSet;
+       u8      CalOneTime;
+
+       u8      VCO_trim;
+
+       u32     FragCount;
+       u32     DMAFix; /* V1_DMA_FIX The variable can be removed if driver want to save mem space for V2. */
+
+       /*
+        * ===============================================
+        * Definition for MAC address
+        * ===============================================
+        */
+       u8      PermanentMacAddress[ETH_ALEN + 2]; /* The Ethernet addr that are stored in EEPROM. + 2 to 8-byte alignment */
+       u8      CurrentMacAddress[ETH_ALEN + 2]; /* The Enthernet addr that are in used. + 2 to 8-byte alignment */
+
+       /*
+        * =========================================
+        * Definition for 802.11
+        * =========================================
+        */
+       u8      *bssid_pointer; /* Used by hal_get_bssid for return value */
+       u8      bssid[8]; /* Only 6 byte will be used. 8 byte is required for read buffer */
+       u8      ssid[32]; /* maximum ssid length is 32 byte */
+
+       u16     AID;
+       u8      ssid_length;
+       u8      Channel;
+
+       u16     ListenInterval;
+       u16     CapabilityInformation;
+
+       u16     BeaconPeriod;
+       u16     ProbeDelay;
+
+       u8      bss_type;/* 0: IBSS_NET or 1:ESS_NET */
+       u8      preamble;/* 0: short preamble, 1: long preamble */
+       u8      slot_time_select; /* 9 or 20 value */
+       u8      phy_type; /* Phy select */
+
+       u32     phy_para[MAX_RF_PARAMETER];
+       u32     phy_number;
+
+       u32     CurrentRadioSw; /* 0:On 1:Off */
+       u32     CurrentRadioHw; /* 0:On 1:Off */
+
+       u8      *power_save_point; /* Used by hal_get_power_save_mode for return value */
+       u8      cwmin;
+       u8      desired_power_save;
+       u8      dtim; /* Is running dtim */
+       u8      mapping_key_replace_index; /* In Key table, the next index be replaced */
+
+       u16     MaxReceiveLifeTime;
+       u16     FragmentThreshold;
+       u16     FragmentThreshold_tmp;
+       u16     cwmax;
+
+       u8      Key_slot[MAX_KEY_TABLE][8]; /* Ownership record for key slot. For Alignment */
+       u32     Key_content[MAX_KEY_TABLE][12]; /* 10DW for each entry + 2 for burst command (Off and On valid bit) */
+       u8      CurrentDefaultKeyIndex;
+       u32     CurrentDefaultKeyLength;
+
+       /*
+        * ==================================================
+        * Variable for each module
+        * ==================================================
+        */
+       struct wb_usb           WbUsb;  /* Need WbUsb.h */
+       struct wb35_reg         reg;    /* Need Wb35Reg.h */
+       struct wb35_tx          Wb35Tx; /* Need Wb35Tx.h */
+       struct wb35_rx          Wb35Rx; /* Need Wb35Rx.h */
+
+       struct timer_list       LEDTimer; /* For LED */
+
+       u32                     LEDpoint; /* For LED */
+
+       u32                     dto_tx_retry_count;
+       u32                     dto_tx_frag_count;
+       u32                     rx_ok_count[13]; /* index=0: total rx ok */
+       u32                     rx_err_count[13]; /* index=0: total rx err */
+
+       /* for Tx debug */
+       u32                     tx_TBTT_start_count;
+       u32                     tx_ETR_count;
+       u32                     tx_WepOn_false_count;
+       u32                     tx_Null_key_count;
+       u32                     tx_retry_count[8];
+
+       u8                      PowerIndexFromEEPROM; /* For 2412MHz */
+       u8                      power_index;
+       u8                      IsWaitJoinComplete; /* TRUE: set join request */
+       u8                      band;
+
+       u16                     SoftwareSet;
+       u16                     Reserved_s;
+
+       u32                     IsInitOK; /* 0: Driver starting 1: Driver init OK */
+
+       /* For Phy calibration */
+       s32                     iq_rsdl_gain_tx_d2;
+       s32                     iq_rsdl_phase_tx_d2;
+       u32                     txvga_setting_for_cal;
+
+       u8                      TxVgaSettingInEEPROM[(((MAX_TXVGA_EEPROM * 2) + 3) & ~0x03)]; /* For EEPROM value */
+       u8                      TxVgaFor24[16]; /* Max is 14, 2 for alignment */
+       struct txvga_for_50             TxVgaFor50[36]; /* 35 channels in 5G. 35x2 = 70 byte. 2 for alignments */
+
+       u16                     Scan_Interval;
+       u16                     RESERVED6;
+
+       /* LED control */
+       u32             LED_control;
+       /*
+        * LED_control 4 byte: Gray_Led_1[3] Gray_Led_0[2] Led[1] Led[0]
+        * Gray_Led
+        *              For Led gray setting
+        * Led
+        *              0: normal control,
+        *                      LED behavior will decide by EEPROM setting
+        *              1: Turn off specific LED
+        *              2: Always on specific LED
+        *              3: slow blinking specific LED
+        *              4: fast blinking specific LED
+        *              5: WPS led control is set. Led0 is Red, Led1 id Green
+        *
+        * Led[1] is parameter for WPS LED mode
+        *              1:InProgress
+        *              2: Error
+        *              3: Session overlap
+        *              4: Success control
+        */
+       u32             LED_LinkOn;     /* Turn LED on control */
+       u32             LED_Scanning;   /* Let LED in scan process control */
+       u32             LED_Blinking;   /* Temp variable for shining */
+       u32             RxByteCountLast;
+       u32             TxByteCountLast;
+
+       /* For global timer */
+       u32             time_count;     /* TICK_TIME_100ms 1 = 100ms */
+};
+
+#endif
diff --git a/drivers/staging/winbond/wbhal_f.h b/drivers/staging/winbond/wbhal_f.h
deleted file mode 100644 (file)
index fc78c14..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * =====================================================================
- * Device related include
- * =====================================================================
-*/
-#include "wb35reg_f.h"
-#include "wb35tx_f.h"
-#include "wb35rx_f.h"
-
-#include "core.h"
-
-/* =====================================================================
- * Function declaration
- * =====================================================================
- */
-void hal_remove_mapping_key(struct hw_data *hw_data, u8 *mac_addr);
-void hal_remove_default_key(struct hw_data *hw_data, u32 index);
-unsigned char hal_set_mapping_key(struct hw_data *adapter, u8 *mac_addr,
-                                 u8 null_key, u8 wep_on, u8 *tx_tsc,
-                                 u8 *rx_tsc, u8 key_type, u8 key_len,
-                                 u8 *key_data);
-unsigned char hal_set_default_key(struct hw_data *adapter, u8 index,
-                                 u8 null_key, u8 wep_on, u8 *tx_tsc,
-                                 u8 *rx_tsc, u8 key_type, u8 key_len,
-                                 u8 *key_data);
-void hal_clear_all_default_key(struct hw_data *hw_data);
-void hal_clear_all_group_key(struct hw_data *hw_data);
-void hal_clear_all_mapping_key(struct hw_data *hw_data);
-void hal_clear_all_key(struct hw_data *hw_data);
-void hal_set_power_save_mode(struct hw_data *hw_data, unsigned char power_save,
-                            unsigned char wakeup, unsigned char dtim);
-void hal_get_power_save_mode(struct hw_data *hw_data, u8 *in_pwr_save);
-void hal_set_slot_time(struct hw_data *hw_data, u8 type);
-
-#define hal_set_atim_window(_A, _ATM)
-
-void hal_start_bss(struct hw_data *hw_data, u8 mac_op_mode);
-
-/* 0:BSS STA 1:IBSS STA */
-void hal_join_request(struct hw_data *hw_data, u8 bss_type);
-
-void hal_stop_sync_bss(struct hw_data *hw_data);
-void hal_resume_sync_bss(struct hw_data *hw_data);
-void hal_set_aid(struct hw_data *hw_data, u16 aid);
-void hal_set_bssid(struct hw_data *hw_data, u8 *bssid);
-void hal_get_bssid(struct hw_data *hw_data, u8 *bssid);
-void hal_set_listen_interval(struct hw_data *hw_data, u16 listen_interval);
-void hal_set_cap_info(struct hw_data *hw_data, u16 capability_info);
-void hal_set_ssid(struct hw_data *hw_data, u8 *ssid, u8 ssid_len);
-void hal_start_tx0(struct hw_data *hw_data);
-
-#define hal_get_cwmin(_A)      ((_A)->cwmin)
-
-void hal_set_cwmax(struct hw_data *hw_data, u16 cwin_max);
-
-#define hal_get_cwmax(_A)      ((_A)->cwmax)
-
-void hal_set_rsn_wpa(struct hw_data *hw_data, u32 *rsn_ie_bitmap,
-                    u32 *rsn_oui_type , unsigned char desired_auth_mode);
-void hal_set_connect_info(struct hw_data *hw_data, unsigned char bo_connect);
-u8 hal_get_est_sq3(struct hw_data *hw_data, u8 count);
-void hal_descriptor_indicate(struct hw_data *hw_data,
-                            struct wb35_descriptor *des);
-u8 hal_get_antenna_number(struct hw_data *hw_data);
-u32 hal_get_bss_pk_cnt(struct hw_data *hw_data);
-
-#define hal_get_region_from_EEPROM(_A) ((_A)->reg.EEPROMRegion)
-#define hal_get_tx_buffer(_A, _B)      Wb35Tx_get_tx_buffer(_A, _B)
-#define hal_software_set(_A)           (_A->SoftwareSet)
-#define hal_driver_init_OK(_A)         (_A->IsInitOK)
-#define hal_rssi_boundary_high(_A)     (_A->RSSI_high)
-#define hal_rssi_boundary_low(_A)      (_A->RSSI_low)
-#define hal_scan_interval(_A)          (_A->Scan_Interval)
-
-#define PHY_DEBUG(msg, args...)
-
-/* return 100ms count */
-#define hal_get_time_count(_P)         (_P->time_count / 10)
-#define hal_detect_error(_P)           (_P->WbUsb.DetectCount)
-
-#define hal_ibss_disconnect(_A)                (hal_stop_sync_bss(_A))
diff --git a/drivers/staging/winbond/wbhal_s.h b/drivers/staging/winbond/wbhal_s.h
deleted file mode 100644 (file)
index 821a1b3..0000000
+++ /dev/null
@@ -1,525 +0,0 @@
-#ifndef __WINBOND_WBHAL_S_H
-#define __WINBOND_WBHAL_S_H
-
-#include <linux/types.h>
-#include <linux/if_ether.h> /* for ETH_ALEN */
-
-#define HAL_LED_SET_MASK       0x001c
-#define HAL_LED_SET_SHIFT      2
-
-/* supported RF type */
-#define RF_MAXIM_2825          0
-#define RF_MAXIM_2827          1
-#define RF_MAXIM_2828          2
-#define RF_MAXIM_2829          3
-#define RF_MAXIM_V1            15
-#define RF_AIROHA_2230         16
-#define RF_AIROHA_7230         17
-#define RF_AIROHA_2230S                18
-#define RF_WB_242              33
-#define RF_WB_242_1            34
-#define RF_DECIDE_BY_INF       255
-
-/*
- * ----------------------------------------------------------------
- * The follow define connect to upper layer
- *     User must modify for connection between HAL and upper layer
- * ----------------------------------------------------------------
- */
-
-/*
- * ==============================
- * Common define
- * ==============================
- */
-/* Bit 5 */
-#define HAL_USB_MODE_BURST(_H)                 (_H->SoftwareSet & 0x20)
-
-/* Scan interval */
-#define SCAN_MAX_CHNL_TIME                     (50)
-
-/* For TxL2 Frame typr recognise */
-#define FRAME_TYPE_802_3_DATA                  0
-#define FRAME_TYPE_802_11_MANAGEMENT           1
-#define FRAME_TYPE_802_11_MANAGEMENT_CHALLENGE 2
-#define FRAME_TYPE_802_11_CONTROL              3
-#define FRAME_TYPE_802_11_DATA                 4
-#define FRAME_TYPE_PROMISCUOUS                 5
-
-/* The follow definition is used for convert the frame------------ */
-#define DOT_11_SEQUENCE_OFFSET                 22 /* Sequence control offset */
-#define DOT_3_TYPE_OFFSET                      12
-#define DOT_11_MAC_HEADER_SIZE                 24
-#define DOT_11_SNAP_SIZE                       6
-#define DOT_11_TYPE_OFFSET                     30 /* The start offset of 802.11 Frame. Type encapsulation. */
-#define DEFAULT_SIFSTIME                       10
-#define DEFAULT_FRAGMENT_THRESHOLD             2346 /* No fragment */
-#define DEFAULT_MSDU_LIFE_TIME                 0xffff
-
-#define LONG_PREAMBLE_PLUS_PLCPHEADER_TIME             (144 + 48)
-#define SHORT_PREAMBLE_PLUS_PLCPHEADER_TIME            (72 + 24)
-#define PREAMBLE_PLUS_SIGNAL_PLUS_SIGNALEXTENSION      (16 + 4 + 6)
-#define Tsym                                           4
-
-/*  Frame Type of Bits (2, 3)----------------------------------- */
-#define MAC_TYPE_MANAGEMENT                    0x00
-#define MAC_TYPE_CONTROL                       0x04
-#define MAC_TYPE_DATA                          0x08
-#define MASK_FRAGMENT_NUMBER                   0x000F
-#define SEQUENCE_NUMBER_SHIFT                  4
-
-#define  HAL_WOL_TYPE_WAKEUP_FRAME             0x01
-#define  HAL_WOL_TYPE_MAGIC_PACKET             0x02
-
-#define HAL_KEYTYPE_WEP40                      0
-#define HAL_KEYTYPE_WEP104                     1
-#define HAL_KEYTYPE_TKIP                       2 /* 128 bit key */
-#define HAL_KEYTYPE_AES_CCMP                   3 /* 128 bit key */
-
-/* For VM state */
-enum {
-       VM_STOP = 0,
-       VM_RUNNING,
-       VM_COMPLETED
-};
-
-/*
- * ================================
- * Normal Key table format
- * ================================
- */
-
-/* The order of KEY index is MAPPING_KEY_START_INDEX > GROUP_KEY_START_INDEX */
-#define MAX_KEY_TABLE                  24 /* 24 entry for storing key data */
-#define GROUP_KEY_START_INDEX          4
-#define MAPPING_KEY_START_INDEX                8
-
-/*
- * =========================================
- * Descriptor
- * =========================================
- */
-#define MAX_DESCRIPTOR_BUFFER_INDEX    8 /* Have to multiple of 2 */
-#define FLAG_ERROR_TX_MASK             0x000000bf
-#define FLAG_ERROR_RX_MASK             0x0000083f
-
-#define FLAG_BAND_RX_MASK              0x10000000 /* Bit 28 */
-
-struct R00_descriptor {
-       union {
-               u32     value;
-#ifdef _BIG_ENDIAN_
-               struct {
-                       u32     R00_packet_or_buffer_status:1;
-                       u32     R00_packet_in_fifo:1;
-                       u32     R00_RESERVED:2;
-                       u32     R00_receive_byte_count:12;
-                       u32     R00_receive_time_index:16;
-               };
-#else
-               struct {
-                       u32     R00_receive_time_index:16;
-                       u32     R00_receive_byte_count:12;
-                       u32     R00_RESERVED:2;
-                       u32     R00_packet_in_fifo:1;
-                       u32     R00_packet_or_buffer_status:1;
-               };
-#endif
-       };
-};
-
-struct T00_descriptor {
-       union {
-               u32     value;
-#ifdef _BIG_ENDIAN_
-               struct {
-                       u32     T00_first_mpdu:1; /* for hardware use */
-                       u32     T00_last_mpdu:1; /* for hardware use */
-                       u32     T00_IsLastMpdu:1;/* 0:not 1:Yes for software used */
-                       u32     T00_IgnoreResult:1;/* The same mechanism with T00 setting. */
-                       u32     T00_RESERVED_ID:2;/* 3 bit ID reserved */
-                       u32     T00_tx_packet_id:4;
-                       u32     T00_RESERVED:4;
-                       u32     T00_header_length:6;
-                       u32     T00_frame_length:12;
-               };
-#else
-               struct {
-                       u32     T00_frame_length:12;
-                       u32     T00_header_length:6;
-                       u32     T00_RESERVED:4;
-                       u32     T00_tx_packet_id:4;
-                       u32     T00_RESERVED_ID:2; /* 3 bit ID reserved */
-                       u32     T00_IgnoreResult:1; /* The same mechanism with T00 setting. */
-                       u32     T00_IsLastMpdu:1; /* 0:not 1:Yes for software used */
-                       u32     T00_last_mpdu:1; /* for hardware use */
-                       u32     T00_first_mpdu:1; /* for hardware use */
-               };
-#endif
-       };
-};
-
-struct R01_descriptor {
-       union {
-               u32     value;
-#ifdef _BIG_ENDIAN_
-               struct {
-                       u32     R01_RESERVED:3;
-                       u32     R01_mod_type:1;
-                       u32     R01_pre_type:1;
-                       u32     R01_data_rate:3;
-                       u32     R01_AGC_state:8;
-                       u32     R01_LNA_state:2;
-                       u32     R01_decryption_method:2;
-                       u32     R01_mic_error:1;
-                       u32     R01_replay:1;
-                       u32     R01_broadcast_frame:1;
-                       u32     R01_multicast_frame:1;
-                       u32     R01_directed_frame:1;
-                       u32     R01_receive_frame_antenna_selection:1;
-                       u32     R01_frame_receive_during_atim_window:1;
-                       u32     R01_protocol_version_error:1;
-                       u32     R01_authentication_frame_icv_error:1;
-                       u32     R01_null_key_to_authentication_frame:1;
-                       u32     R01_icv_error:1;
-                       u32     R01_crc_error:1;
-               };
-#else
-               struct {
-                       u32     R01_crc_error:1;
-                       u32     R01_icv_error:1;
-                       u32     R01_null_key_to_authentication_frame:1;
-                       u32     R01_authentication_frame_icv_error:1;
-                       u32     R01_protocol_version_error:1;
-                       u32     R01_frame_receive_during_atim_window:1;
-                       u32     R01_receive_frame_antenna_selection:1;
-                       u32     R01_directed_frame:1;
-                       u32     R01_multicast_frame:1;
-                       u32     R01_broadcast_frame:1;
-                       u32     R01_replay:1;
-                       u32     R01_mic_error:1;
-                       u32     R01_decryption_method:2;
-                       u32     R01_LNA_state:2;
-                       u32     R01_AGC_state:8;
-                       u32     R01_data_rate:3;
-                       u32     R01_pre_type:1;
-                       u32     R01_mod_type:1;
-                       u32     R01_RESERVED:3;
-               };
-#endif
-       };
-};
-
-struct T01_descriptor {
-       union {
-               u32     value;
-#ifdef _BIG_ENDIAN_
-               struct {
-                       u32     T01_rts_cts_duration:16;
-                       u32     T01_fall_back_rate:3;
-                       u32     T01_add_rts:1;
-                       u32     T01_add_cts:1;
-                       u32     T01_modulation_type:1;
-                       u32     T01_plcp_header_length:1;
-                       u32     T01_transmit_rate:3;
-                       u32     T01_wep_id:2;
-                       u32     T01_add_challenge_text:1;
-                       u32     T01_inhibit_crc:1;
-                       u32     T01_loop_back_wep_mode:1;
-                       u32     T01_retry_abort_ebable:1;
-               };
-#else
-               struct {
-                       u32     T01_retry_abort_ebable:1;
-                       u32     T01_loop_back_wep_mode:1;
-                       u32     T01_inhibit_crc:1;
-                       u32     T01_add_challenge_text:1;
-                       u32     T01_wep_id:2;
-                       u32     T01_transmit_rate:3;
-                       u32     T01_plcp_header_length:1;
-                       u32     T01_modulation_type:1;
-                       u32     T01_add_cts:1;
-                       u32     T01_add_rts:1;
-                       u32     T01_fall_back_rate:3;
-                       u32     T01_rts_cts_duration:16;
-               };
-#endif
-       };
-};
-
-struct T02_descriptor {
-       union {
-               u32     value;
-#ifdef _BIG_ENDIAN_
-               struct {
-                       u32     T02_IsLastMpdu:1; /* The same mechanism with T00 setting */
-                       u32     T02_IgnoreResult:1; /* The same mechanism with T00 setting. */
-                       u32     T02_RESERVED_ID:2; /* The same mechanism with T00 setting */
-                       u32     T02_Tx_PktID:4;
-                       u32     T02_MPDU_Cnt:4;
-                       u32     T02_RTS_Cnt:4;
-                       u32     T02_RESERVED:7;
-                       u32     T02_transmit_complete:1;
-                       u32     T02_transmit_abort_due_to_TBTT:1;
-                       u32     T02_effective_transmission_rate:1;
-                       u32     T02_transmit_without_encryption_due_to_wep_on_false:1;
-                       u32     T02_discard_due_to_null_wep_key:1;
-                       u32     T02_RESERVED_1:1;
-                       u32     T02_out_of_MaxTxMSDULiftTime:1;
-                       u32     T02_transmit_abort:1;
-                       u32     T02_transmit_fail:1;
-               };
-#else
-               struct {
-                       u32     T02_transmit_fail:1;
-                       u32     T02_transmit_abort:1;
-                       u32     T02_out_of_MaxTxMSDULiftTime:1;
-                       u32     T02_RESERVED_1:1;
-                       u32     T02_discard_due_to_null_wep_key:1;
-                       u32     T02_transmit_without_encryption_due_to_wep_on_false:1;
-                       u32     T02_effective_transmission_rate:1;
-                       u32     T02_transmit_abort_due_to_TBTT:1;
-                       u32     T02_transmit_complete:1;
-                       u32     T02_RESERVED:7;
-                       u32     T02_RTS_Cnt:4;
-                       u32     T02_MPDU_Cnt:4;
-                       u32     T02_Tx_PktID:4;
-                       u32     T02_RESERVED_ID:2; /* The same mechanism with T00 setting */
-                       u32     T02_IgnoreResult:1; /* The same mechanism with T00 setting. */
-                       u32     T02_IsLastMpdu:1; /* The same mechanism with T00 setting */
-               };
-#endif
-       };
-};
-
-struct wb35_descriptor { /* Skip length = 8 DWORD */
-       /* ID for descriptor ---, The field doesn't be cleard in the operation of Descriptor definition */
-       u8      Descriptor_ID;
-       /* ----------------------The above region doesn't be cleared by DESCRIPTOR_RESET------ */
-       u8      RESERVED[3];
-
-       u16     FragmentThreshold;
-       u8      InternalUsed; /* Only can be used by operation of descriptor definition */
-       u8      Type; /* 0: 802.3 1:802.11 data frame 2:802.11 management frame */
-
-       u8      PreambleMode;/* 0: short 1:long */
-       u8      TxRate;
-       u8      FragmentCount;
-       u8      EapFix; /* For speed up key install */
-
-       /* For R00 and T00 ------------------------------ */
-       union {
-               struct R00_descriptor   R00;
-               struct T00_descriptor   T00;
-       };
-
-       /* For R01 and T01 ------------------------------ */
-       union {
-               struct R01_descriptor   R01;
-               struct T01_descriptor   T01;
-       };
-
-       /* For R02 and T02 ------------------------------ */
-       union {
-               u32             R02;
-               struct T02_descriptor   T02;
-       };
-
-       /* For R03 and T03 ------------------------------ */
-       /* For software used */
-       union {
-               u32     R03;
-               u32     T03;
-               struct {
-                       u8      buffer_number;
-                       u8      buffer_start_index;
-                       u16     buffer_total_size;
-               };
-       };
-
-       /* For storing the buffer */
-       u16     buffer_size[MAX_DESCRIPTOR_BUFFER_INDEX];
-       void    *buffer_address[MAX_DESCRIPTOR_BUFFER_INDEX];
-};
-
-
-#define DEFAULT_NULL_PACKET_COUNT      180000  /* 180 seconds */
-
-#define MAX_TXVGA_EEPROM               9       /* How many word(u16) of EEPROM will be used for TxVGA */
-#define MAX_RF_PARAMETER               32
-
-struct txvga_for_50 {
-       u8      ChanNo;
-       u8      TxVgaValue;
-};
-
-/*
- * ==============================================
- * Device related include
- * ==============================================
- */
-
-#include "wbusb_s.h"
-#include "wb35reg_s.h"
-#include "wb35tx_s.h"
-#include "wb35rx_s.h"
-
-/* For Hal using ============================================ */
-struct hw_data {
-       /* For compatible with 33 */
-       u32     revision;
-       u32     BB3c_cal; /* The value for Tx calibration comes from EEPROM */
-       u32     BB54_cal; /* The value for Rx calibration comes from EEPROM */
-
-       /* For surprise remove */
-       u32     SurpriseRemove; /* 0: Normal 1: Surprise remove */
-       u8      IsKeyPreSet;
-       u8      CalOneTime;
-
-       u8      VCO_trim;
-
-       u32     FragCount;
-       u32     DMAFix; /* V1_DMA_FIX The variable can be removed if driver want to save mem space for V2. */
-
-       /*
-        * ===============================================
-        * Definition for MAC address
-        * ===============================================
-        */
-       u8      PermanentMacAddress[ETH_ALEN + 2]; /* The Ethernet addr that are stored in EEPROM. + 2 to 8-byte alignment */
-       u8      CurrentMacAddress[ETH_ALEN + 2]; /* The Enthernet addr that are in used. + 2 to 8-byte alignment */
-
-       /*
-        * =========================================
-        * Definition for 802.11
-        * =========================================
-        */
-       u8      *bssid_pointer; /* Used by hal_get_bssid for return value */
-       u8      bssid[8]; /* Only 6 byte will be used. 8 byte is required for read buffer */
-       u8      ssid[32]; /* maximum ssid length is 32 byte */
-
-       u16     AID;
-       u8      ssid_length;
-       u8      Channel;
-
-       u16     ListenInterval;
-       u16     CapabilityInformation;
-
-       u16     BeaconPeriod;
-       u16     ProbeDelay;
-
-       u8      bss_type;/* 0: IBSS_NET or 1:ESS_NET */
-       u8      preamble;/* 0: short preamble, 1: long preamble */
-       u8      slot_time_select; /* 9 or 20 value */
-       u8      phy_type; /* Phy select */
-
-       u32     phy_para[MAX_RF_PARAMETER];
-       u32     phy_number;
-
-       u32     CurrentRadioSw; /* 0:On 1:Off */
-       u32     CurrentRadioHw; /* 0:On 1:Off */
-
-       u8      *power_save_point; /* Used by hal_get_power_save_mode for return value */
-       u8      cwmin;
-       u8      desired_power_save;
-       u8      dtim; /* Is running dtim */
-       u8      mapping_key_replace_index; /* In Key table, the next index be replaced */
-
-       u16     MaxReceiveLifeTime;
-       u16     FragmentThreshold;
-       u16     FragmentThreshold_tmp;
-       u16     cwmax;
-
-       u8      Key_slot[MAX_KEY_TABLE][8]; /* Ownership record for key slot. For Alignment */
-       u32     Key_content[MAX_KEY_TABLE][12]; /* 10DW for each entry + 2 for burst command (Off and On valid bit) */
-       u8      CurrentDefaultKeyIndex;
-       u32     CurrentDefaultKeyLength;
-
-       /*
-        * ==================================================
-        * Variable for each module
-        * ==================================================
-        */
-       struct wb_usb           WbUsb;  /* Need WbUsb.h */
-       struct wb35_reg         reg;    /* Need Wb35Reg.h */
-       struct wb35_tx          Wb35Tx; /* Need Wb35Tx.h */
-       struct wb35_rx          Wb35Rx; /* Need Wb35Rx.h */
-
-       struct timer_list       LEDTimer; /* For LED */
-
-       u32                     LEDpoint; /* For LED */
-
-       u32                     dto_tx_retry_count;
-       u32                     dto_tx_frag_count;
-       u32                     rx_ok_count[13]; /* index=0: total rx ok */
-       u32                     rx_err_count[13]; /* index=0: total rx err */
-
-       /* for Tx debug */
-       u32                     tx_TBTT_start_count;
-       u32                     tx_ETR_count;
-       u32                     tx_WepOn_false_count;
-       u32                     tx_Null_key_count;
-       u32                     tx_retry_count[8];
-
-       u8                      PowerIndexFromEEPROM; /* For 2412MHz */
-       u8                      power_index;
-       u8                      IsWaitJoinComplete; /* TRUE: set join request */
-       u8                      band;
-
-       u16                     SoftwareSet;
-       u16                     Reserved_s;
-
-       u32                     IsInitOK; /* 0: Driver starting 1: Driver init OK */
-
-       /* For Phy calibration */
-       s32                     iq_rsdl_gain_tx_d2;
-       s32                     iq_rsdl_phase_tx_d2;
-       u32                     txvga_setting_for_cal;
-
-       u8                      TxVgaSettingInEEPROM[(((MAX_TXVGA_EEPROM * 2) + 3) & ~0x03)]; /* For EEPROM value */
-       u8                      TxVgaFor24[16]; /* Max is 14, 2 for alignment */
-       struct txvga_for_50             TxVgaFor50[36]; /* 35 channels in 5G. 35x2 = 70 byte. 2 for alignments */
-
-       u16                     Scan_Interval;
-       u16                     RESERVED6;
-
-       /* LED control */
-       u32             LED_control;
-       /*
-        * LED_control 4 byte: Gray_Led_1[3] Gray_Led_0[2] Led[1] Led[0]
-        * Gray_Led
-        *              For Led gray setting
-        * Led
-        *              0: normal control,
-        *                      LED behavior will decide by EEPROM setting
-        *              1: Turn off specific LED
-        *              2: Always on specific LED
-        *              3: slow blinking specific LED
-        *              4: fast blinking specific LED
-        *              5: WPS led control is set. Led0 is Red, Led1 id Green
-        *
-        * Led[1] is parameter for WPS LED mode
-        *              1:InProgress
-        *              2: Error
-        *              3: Session overlap
-        *              4: Success control
-        */
-       u32             LED_LinkOn;     /* Turn LED on control */
-       u32             LED_Scanning;   /* Let LED in scan process control */
-       u32             LED_Blinking;   /* Temp variable for shining */
-       u32             RxByteCountLast;
-       u32             TxByteCountLast;
-
-       atomic_t        SurpriseRemoveCount;
-
-       /* For global timer */
-       u32             time_count;     /* TICK_TIME_100ms 1 = 100ms */
-
-       /* For error recover */
-       u32             HwStop;
-
-       /* For avoid AP disconnect */
-       u32             NullPacketCount;
-};
-
-#endif
index 3f60cf7e6ec13554cb9d43d2475674126775b2e8..dcb6d5b63d76ccee8c775ff79c39d3c7cbb072f0 100644 (file)
 #include "mds_f.h"
 #include "mlmetxrx_f.h"
 #include "mto.h"
-#include "wbhal_f.h"
+#include "wbhal.h"
+#include "wb35reg_f.h"
+#include "wb35tx_f.h"
+#include "wb35rx_f.h"
 #include "wblinux_f.h"
 
 MODULE_DESCRIPTION("IS89C35 802.11bg WLAN USB Driver");
@@ -608,15 +611,6 @@ static void hal_led_control(unsigned long data)
                        }
                        break;
                }
-
-               /* Active send null packet to avoid AP disconnect */
-               if (pHwData->LED_LinkOn) {
-                       pHwData->NullPacketCount += TimeInterval;
-                       if (pHwData->NullPacketCount >=
-                           DEFAULT_NULL_PACKET_COUNT) {
-                               pHwData->NullPacketCount = 0;
-                       }
-               }
        }
 
        pHwData->time_count += TimeInterval;
@@ -860,8 +854,6 @@ static void hal_halt(struct hw_data *pHwData)
 
 static void wb35_hw_halt(struct wbsoft_priv *adapter)
 {
-       Mds_Destroy(adapter);
-
        /* Turn off Rx and Tx hardware ability */
        hal_stop(&adapter->sHwData);
 #ifdef _PE_USB_INI_DUMP_
index e4c8804ac37d81821d3f5bec356cd0ba9348aeda..9b833b30ae6250de88766c86bd38c79b59906600 100644 (file)
@@ -42,7 +42,7 @@ static ssize_t show_tallies(struct device *d, struct device_attribute *attr,
     CFG_HERMES_TALLIES_STRCT tallies;
     ssize_t ret = -EINVAL;
 
-    read_lock(&dev_base_lock);
+    rcu_read_lock();
     if (dev_isalive(dev)) {
        wl_lock(lp, &flags);
 
@@ -102,7 +102,7 @@ static ssize_t show_tallies(struct device *d, struct device_attribute *attr,
            }
     }
 
-    read_unlock(&dev_base_lock);
+    rcu_read_unlock();
     return ret;
 }
 
index 4f73d095c3ac567540bde50fae8fbf703d145e12..36ec45b84fcaf264ab53fbe5ac070dfe8469cb05 100644 (file)
@@ -472,9 +472,11 @@ unsigned char XGIfb_query_north_bridge_space(struct xgi_hw_device_info *pXGIhw_e
                        break;
                }
 
-               pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridge_id, pdev);
-               if (pdev)
+               pdev = pci_get_device(PCI_VENDOR_ID_SI, nbridge_id, pdev);
+               if (pdev) {
                        valid_pdev = 1;
+                       pci_dev_put(pdev);
+               }
        }
 
        if (!valid_pdev) {
diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile
new file mode 100644 (file)
index 0000000..c43ef48
--- /dev/null
@@ -0,0 +1,11 @@
+obj-y                          += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
+                                  tty_buffer.o tty_port.o tty_mutex.o
+obj-$(CONFIG_LEGACY_PTYS)      += pty.o
+obj-$(CONFIG_UNIX98_PTYS)      += pty.o
+obj-$(CONFIG_AUDIT)            += tty_audit.o
+obj-$(CONFIG_MAGIC_SYSRQ)      += sysrq.o
+obj-$(CONFIG_N_HDLC)           += n_hdlc.o
+obj-$(CONFIG_N_GSM)            += n_gsm.o
+obj-$(CONFIG_R3964)            += n_r3964.o
+
+obj-y                          += vt/
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
new file mode 100644 (file)
index 0000000..04ef3ef
--- /dev/null
@@ -0,0 +1,2763 @@
+/*
+ * n_gsm.c GSM 0710 tty multiplexor
+ * Copyright (c) 2009/10 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *     * THIS IS A DEVELOPMENT SNAPSHOT IT IS NOT A FINAL RELEASE *
+ *
+ * TO DO:
+ *     Mostly done:    ioctls for setting modes/timing
+ *     Partly done:    hooks so you can pull off frames to non tty devs
+ *     Restart DLCI 0 when it closes ?
+ *     Test basic encoding
+ *     Improve the tx engine
+ *     Resolve tx side locking by adding a queue_head and routing
+ *             all control traffic via it
+ *     General tidy/document
+ *     Review the locking/move to refcounts more (mux now moved to an
+ *             alloc/free model ready)
+ *     Use newest tty open/close port helpers and install hooks
+ *     What to do about power functions ?
+ *     Termios setting and negotiation
+ *     Do we need a 'which mux are you' ioctl to correlate mux and tty sets
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/ctype.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/bitops.h>
+#include <linux/file.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/tty_flip.h>
+#include <linux/tty_driver.h>
+#include <linux/serial.h>
+#include <linux/kfifo.h>
+#include <linux/skbuff.h>
+#include <linux/gsmmux.h>
+
+static int debug;
+module_param(debug, int, 0600);
+
+#define T1     (HZ/10)
+#define T2     (HZ/3)
+#define N2     3
+
+/* Use long timers for testing at low speed with debug on */
+#ifdef DEBUG_TIMING
+#define T1     HZ
+#define T2     (2 * HZ)
+#endif
+
+/* Semi-arbitary buffer size limits. 0710 is normally run with 32-64 byte
+   limits so this is plenty */
+#define MAX_MRU 512
+#define MAX_MTU 512
+
+/*
+ *     Each block of data we have queued to go out is in the form of
+ *     a gsm_msg which holds everything we need in a link layer independant
+ *     format
+ */
+
+struct gsm_msg {
+       struct gsm_msg *next;
+       u8 addr;                /* DLCI address + flags */
+       u8 ctrl;                /* Control byte + flags */
+       unsigned int len;       /* Length of data block (can be zero) */
+       unsigned char *data;    /* Points into buffer but not at the start */
+       unsigned char buffer[0];
+};
+
+/*
+ *     Each active data link has a gsm_dlci structure associated which ties
+ *     the link layer to an optional tty (if the tty side is open). To avoid
+ *     complexity right now these are only ever freed up when the mux is
+ *     shut down.
+ *
+ *     At the moment we don't free DLCI objects until the mux is torn down
+ *     this avoid object life time issues but might be worth review later.
+ */
+
+struct gsm_dlci {
+       struct gsm_mux *gsm;
+       int addr;
+       int state;
+#define DLCI_CLOSED            0
+#define DLCI_OPENING           1       /* Sending SABM not seen UA */
+#define DLCI_OPEN              2       /* SABM/UA complete */
+#define DLCI_CLOSING           3       /* Sending DISC not seen UA/DM */
+
+       /* Link layer */
+       spinlock_t lock;        /* Protects the internal state */
+       struct timer_list t1;   /* Retransmit timer for SABM and UA */
+       int retries;
+       /* Uplink tty if active */
+       struct tty_port port;   /* The tty bound to this DLCI if there is one */
+       struct kfifo *fifo;     /* Queue fifo for the DLCI */
+       struct kfifo _fifo;     /* For new fifo API porting only */
+       int adaption;           /* Adaption layer in use */
+       u32 modem_rx;           /* Our incoming virtual modem lines */
+       u32 modem_tx;           /* Our outgoing modem lines */
+       int dead;               /* Refuse re-open */
+       /* Flow control */
+       int throttled;          /* Private copy of throttle state */
+       int constipated;        /* Throttle status for outgoing */
+       /* Packetised I/O */
+       struct sk_buff *skb;    /* Frame being sent */
+       struct sk_buff_head skb_list;   /* Queued frames */
+       /* Data handling callback */
+       void (*data)(struct gsm_dlci *dlci, u8 *data, int len);
+};
+
+/* DLCI 0, 62/63 are special or reseved see gsmtty_open */
+
+#define NUM_DLCI               64
+
+/*
+ *     DLCI 0 is used to pass control blocks out of band of the data
+ *     flow (and with a higher link priority). One command can be outstanding
+ *     at a time and we use this structure to manage them. They are created
+ *     and destroyed by the user context, and updated by the receive paths
+ *     and timers
+ */
+
+struct gsm_control {
+       u8 cmd;         /* Command we are issuing */
+       u8 *data;       /* Data for the command in case we retransmit */
+       int len;        /* Length of block for retransmission */
+       int done;       /* Done flag */
+       int error;      /* Error if any */
+};
+
+/*
+ *     Each GSM mux we have is represented by this structure. If we are
+ *     operating as an ldisc then we use this structure as our ldisc
+ *     state. We need to sort out lifetimes and locking with respect
+ *     to the gsm mux array. For now we don't free DLCI objects that
+ *     have been instantiated until the mux itself is terminated.
+ *
+ *     To consider further: tty open versus mux shutdown.
+ */
+
+struct gsm_mux {
+       struct tty_struct *tty;         /* The tty our ldisc is bound to */
+       spinlock_t lock;
+
+       /* Events on the GSM channel */
+       wait_queue_head_t event;
+
+       /* Bits for GSM mode decoding */
+
+       /* Framing Layer */
+       unsigned char *buf;
+       int state;
+#define GSM_SEARCH             0
+#define GSM_START              1
+#define GSM_ADDRESS            2
+#define GSM_CONTROL            3
+#define GSM_LEN                        4
+#define GSM_DATA               5
+#define GSM_FCS                        6
+#define GSM_OVERRUN            7
+       unsigned int len;
+       unsigned int address;
+       unsigned int count;
+       int escape;
+       int encoding;
+       u8 control;
+       u8 fcs;
+       u8 *txframe;                    /* TX framing buffer */
+
+       /* Methods for the receiver side */
+       void (*receive)(struct gsm_mux *gsm, u8 ch);
+       void (*error)(struct gsm_mux *gsm, u8 ch, u8 flag);
+       /* And transmit side */
+       int (*output)(struct gsm_mux *mux, u8 *data, int len);
+
+       /* Link Layer */
+       unsigned int mru;
+       unsigned int mtu;
+       int initiator;                  /* Did we initiate connection */
+       int dead;                       /* Has the mux been shut down */
+       struct gsm_dlci *dlci[NUM_DLCI];
+       int constipated;                /* Asked by remote to shut up */
+
+       spinlock_t tx_lock;
+       unsigned int tx_bytes;          /* TX data outstanding */
+#define TX_THRESH_HI           8192
+#define TX_THRESH_LO           2048
+       struct gsm_msg *tx_head;        /* Pending data packets */
+       struct gsm_msg *tx_tail;
+
+       /* Control messages */
+       struct timer_list t2_timer;     /* Retransmit timer for commands */
+       int cretries;                   /* Command retry counter */
+       struct gsm_control *pending_cmd;/* Our current pending command */
+       spinlock_t control_lock;        /* Protects the pending command */
+
+       /* Configuration */
+       int adaption;           /* 1 or 2 supported */
+       u8 ftype;               /* UI or UIH */
+       int t1, t2;             /* Timers in 1/100th of a sec */
+       int n2;                 /* Retry count */
+
+       /* Statistics (not currently exposed) */
+       unsigned long bad_fcs;
+       unsigned long malformed;
+       unsigned long io_error;
+       unsigned long bad_size;
+       unsigned long unsupported;
+};
+
+
+/*
+ *     Mux objects - needed so that we can translate a tty index into the
+ *     relevant mux and DLCI.
+ */
+
+#define MAX_MUX                4                       /* 256 minors */
+static struct gsm_mux *gsm_mux[MAX_MUX];       /* GSM muxes */
+static spinlock_t gsm_mux_lock;
+
+/*
+ *     This section of the driver logic implements the GSM encodings
+ *     both the basic and the 'advanced'. Reliable transport is not
+ *     supported.
+ */
+
+#define CR                     0x02
+#define EA                     0x01
+#define        PF                      0x10
+
+/* I is special: the rest are ..*/
+#define RR                     0x01
+#define UI                     0x03
+#define RNR                    0x05
+#define REJ                    0x09
+#define DM                     0x0F
+#define SABM                   0x2F
+#define DISC                   0x43
+#define UA                     0x63
+#define        UIH                     0xEF
+
+/* Channel commands */
+#define CMD_NSC                        0x09
+#define CMD_TEST               0x11
+#define CMD_PSC                        0x21
+#define CMD_RLS                        0x29
+#define CMD_FCOFF              0x31
+#define CMD_PN                 0x41
+#define CMD_RPN                        0x49
+#define CMD_FCON               0x51
+#define CMD_CLD                        0x61
+#define CMD_SNC                        0x69
+#define CMD_MSC                        0x71
+
+/* Virtual modem bits */
+#define MDM_FC                 0x01
+#define MDM_RTC                        0x02
+#define MDM_RTR                        0x04
+#define MDM_IC                 0x20
+#define MDM_DV                 0x40
+
+#define GSM0_SOF               0xF9
+#define GSM1_SOF               0x7E
+#define GSM1_ESCAPE            0x7D
+#define GSM1_ESCAPE_BITS       0x20
+#define XON                    0x11
+#define XOFF                   0x13
+
+static const struct tty_port_operations gsm_port_ops;
+
+/*
+ *     CRC table for GSM 0710
+ */
+
+static const u8 gsm_fcs8[256] = {
+       0x00, 0x91, 0xE3, 0x72, 0x07, 0x96, 0xE4, 0x75,
+       0x0E, 0x9F, 0xED, 0x7C, 0x09, 0x98, 0xEA, 0x7B,
+       0x1C, 0x8D, 0xFF, 0x6E, 0x1B, 0x8A, 0xF8, 0x69,
+       0x12, 0x83, 0xF1, 0x60, 0x15, 0x84, 0xF6, 0x67,
+       0x38, 0xA9, 0xDB, 0x4A, 0x3F, 0xAE, 0xDC, 0x4D,
+       0x36, 0xA7, 0xD5, 0x44, 0x31, 0xA0, 0xD2, 0x43,
+       0x24, 0xB5, 0xC7, 0x56, 0x23, 0xB2, 0xC0, 0x51,
+       0x2A, 0xBB, 0xC9, 0x58, 0x2D, 0xBC, 0xCE, 0x5F,
+       0x70, 0xE1, 0x93, 0x02, 0x77, 0xE6, 0x94, 0x05,
+       0x7E, 0xEF, 0x9D, 0x0C, 0x79, 0xE8, 0x9A, 0x0B,
+       0x6C, 0xFD, 0x8F, 0x1E, 0x6B, 0xFA, 0x88, 0x19,
+       0x62, 0xF3, 0x81, 0x10, 0x65, 0xF4, 0x86, 0x17,
+       0x48, 0xD9, 0xAB, 0x3A, 0x4F, 0xDE, 0xAC, 0x3D,
+       0x46, 0xD7, 0xA5, 0x34, 0x41, 0xD0, 0xA2, 0x33,
+       0x54, 0xC5, 0xB7, 0x26, 0x53, 0xC2, 0xB0, 0x21,
+       0x5A, 0xCB, 0xB9, 0x28, 0x5D, 0xCC, 0xBE, 0x2F,
+       0xE0, 0x71, 0x03, 0x92, 0xE7, 0x76, 0x04, 0x95,
+       0xEE, 0x7F, 0x0D, 0x9C, 0xE9, 0x78, 0x0A, 0x9B,
+       0xFC, 0x6D, 0x1F, 0x8E, 0xFB, 0x6A, 0x18, 0x89,
+       0xF2, 0x63, 0x11, 0x80, 0xF5, 0x64, 0x16, 0x87,
+       0xD8, 0x49, 0x3B, 0xAA, 0xDF, 0x4E, 0x3C, 0xAD,
+       0xD6, 0x47, 0x35, 0xA4, 0xD1, 0x40, 0x32, 0xA3,
+       0xC4, 0x55, 0x27, 0xB6, 0xC3, 0x52, 0x20, 0xB1,
+       0xCA, 0x5B, 0x29, 0xB8, 0xCD, 0x5C, 0x2E, 0xBF,
+       0x90, 0x01, 0x73, 0xE2, 0x97, 0x06, 0x74, 0xE5,
+       0x9E, 0x0F, 0x7D, 0xEC, 0x99, 0x08, 0x7A, 0xEB,
+       0x8C, 0x1D, 0x6F, 0xFE, 0x8B, 0x1A, 0x68, 0xF9,
+       0x82, 0x13, 0x61, 0xF0, 0x85, 0x14, 0x66, 0xF7,
+       0xA8, 0x39, 0x4B, 0xDA, 0xAF, 0x3E, 0x4C, 0xDD,
+       0xA6, 0x37, 0x45, 0xD4, 0xA1, 0x30, 0x42, 0xD3,
+       0xB4, 0x25, 0x57, 0xC6, 0xB3, 0x22, 0x50, 0xC1,
+       0xBA, 0x2B, 0x59, 0xC8, 0xBD, 0x2C, 0x5E, 0xCF
+};
+
+#define INIT_FCS       0xFF
+#define GOOD_FCS       0xCF
+
+/**
+ *     gsm_fcs_add     -       update FCS
+ *     @fcs: Current FCS
+ *     @c: Next data
+ *
+ *     Update the FCS to include c. Uses the algorithm in the specification
+ *     notes.
+ */
+
+static inline u8 gsm_fcs_add(u8 fcs, u8 c)
+{
+       return gsm_fcs8[fcs ^ c];
+}
+
+/**
+ *     gsm_fcs_add_block       -       update FCS for a block
+ *     @fcs: Current FCS
+ *     @c: buffer of data
+ *     @len: length of buffer
+ *
+ *     Update the FCS to include c. Uses the algorithm in the specification
+ *     notes.
+ */
+
+static inline u8 gsm_fcs_add_block(u8 fcs, u8 *c, int len)
+{
+       while (len--)
+               fcs = gsm_fcs8[fcs ^ *c++];
+       return fcs;
+}
+
+/**
+ *     gsm_read_ea             -       read a byte into an EA
+ *     @val: variable holding value
+ *     c: byte going into the EA
+ *
+ *     Processes one byte of an EA. Updates the passed variable
+ *     and returns 1 if the EA is now completely read
+ */
+
+static int gsm_read_ea(unsigned int *val, u8 c)
+{
+       /* Add the next 7 bits into the value */
+       *val <<= 7;
+       *val |= c >> 1;
+       /* Was this the last byte of the EA 1 = yes*/
+       return c & EA;
+}
+
+/**
+ *     gsm_encode_modem        -       encode modem data bits
+ *     @dlci: DLCI to encode from
+ *
+ *     Returns the correct GSM encoded modem status bits (6 bit field) for
+ *     the current status of the DLCI and attached tty object
+ */
+
+static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
+{
+       u8 modembits = 0;
+       /* FC is true flow control not modem bits */
+       if (dlci->throttled)
+               modembits |= MDM_FC;
+       if (dlci->modem_tx & TIOCM_DTR)
+               modembits |= MDM_RTC;
+       if (dlci->modem_tx & TIOCM_RTS)
+               modembits |= MDM_RTR;
+       if (dlci->modem_tx & TIOCM_RI)
+               modembits |= MDM_IC;
+       if (dlci->modem_tx & TIOCM_CD)
+               modembits |= MDM_DV;
+       return modembits;
+}
+
+/**
+ *     gsm_print_packet        -       display a frame for debug
+ *     @hdr: header to print before decode
+ *     @addr: address EA from the frame
+ *     @cr: C/R bit from the frame
+ *     @control: control including PF bit
+ *     @data: following data bytes
+ *     @dlen: length of data
+ *
+ *     Displays a packet in human readable format for debugging purposes. The
+ *     style is based on amateur radio LAP-B dump display.
+ */
+
+static void gsm_print_packet(const char *hdr, int addr, int cr,
+                                       u8 control, const u8 *data, int dlen)
+{
+       if (!(debug & 1))
+               return;
+
+       printk(KERN_INFO "%s %d) %c: ", hdr, addr, "RC"[cr]);
+
+       switch (control & ~PF) {
+       case SABM:
+               printk(KERN_CONT "SABM");
+               break;
+       case UA:
+               printk(KERN_CONT "UA");
+               break;
+       case DISC:
+               printk(KERN_CONT "DISC");
+               break;
+       case DM:
+               printk(KERN_CONT "DM");
+               break;
+       case UI:
+               printk(KERN_CONT "UI");
+               break;
+       case UIH:
+               printk(KERN_CONT "UIH");
+               break;
+       default:
+               if (!(control & 0x01)) {
+                       printk(KERN_CONT "I N(S)%d N(R)%d",
+                               (control & 0x0E) >> 1, (control & 0xE)>> 5);
+               } else switch (control & 0x0F) {
+               case RR:
+                       printk("RR(%d)", (control & 0xE0) >> 5);
+                       break;
+               case RNR:
+                       printk("RNR(%d)", (control & 0xE0) >> 5);
+                       break;
+               case REJ:
+                       printk("REJ(%d)", (control & 0xE0) >> 5);
+                       break;
+               default:
+                       printk(KERN_CONT "[%02X]", control);
+               }
+       }
+
+       if (control & PF)
+               printk(KERN_CONT "(P)");
+       else
+               printk(KERN_CONT "(F)");
+
+       if (dlen) {
+               int ct = 0;
+               while (dlen--) {
+                       if (ct % 8 == 0)
+                               printk(KERN_CONT "\n    ");
+                       printk(KERN_CONT "%02X ", *data++);
+                       ct++;
+               }
+       }
+       printk(KERN_CONT "\n");
+}
+
+
+/*
+ *     Link level transmission side
+ */
+
+/**
+ *     gsm_stuff_packet        -       bytestuff a packet
+ *     @ibuf: input
+ *     @obuf: output
+ *     @len: length of input
+ *
+ *     Expand a buffer by bytestuffing it. The worst case size change
+ *     is doubling and the caller is responsible for handing out
+ *     suitable sized buffers.
+ */
+
+static int gsm_stuff_frame(const u8 *input, u8 *output, int len)
+{
+       int olen = 0;
+       while (len--) {
+               if (*input == GSM1_SOF || *input == GSM1_ESCAPE
+                   || *input == XON || *input == XOFF) {
+                       *output++ = GSM1_ESCAPE;
+                       *output++ = *input++ ^ GSM1_ESCAPE_BITS;
+                       olen++;
+               } else
+                       *output++ = *input++;
+               olen++;
+       }
+       return olen;
+}
+
+static void hex_packet(const unsigned char *p, int len)
+{
+       int i;
+       for (i = 0; i < len; i++) {
+               if (i && (i % 16) == 0)
+                       printk("\n");
+               printk("%02X ", *p++);
+       }
+       printk("\n");
+}
+
+/**
+ *     gsm_send        -       send a control frame
+ *     @gsm: our GSM mux
+ *     @addr: address for control frame
+ *     @cr: command/response bit
+ *     @control:  control byte including PF bit
+ *
+ *     Format up and transmit a control frame. These do not go via the
+ *     queueing logic as they should be transmitted ahead of data when
+ *     they are needed.
+ *
+ *     FIXME: Lock versus data TX path
+ */
+
+static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
+{
+       int len;
+       u8 cbuf[10];
+       u8 ibuf[3];
+
+       switch (gsm->encoding) {
+       case 0:
+               cbuf[0] = GSM0_SOF;
+               cbuf[1] = (addr << 2) | (cr << 1) | EA;
+               cbuf[2] = control;
+               cbuf[3] = EA;   /* Length of data = 0 */
+               cbuf[4] = 0xFF - gsm_fcs_add_block(INIT_FCS, cbuf + 1, 3);
+               cbuf[5] = GSM0_SOF;
+               len = 6;
+               break;
+       case 1:
+       case 2:
+               /* Control frame + packing (but not frame stuffing) in mode 1 */
+               ibuf[0] = (addr << 2) | (cr << 1) | EA;
+               ibuf[1] = control;
+               ibuf[2] = 0xFF - gsm_fcs_add_block(INIT_FCS, ibuf, 2);
+               /* Stuffing may double the size worst case */
+               len = gsm_stuff_frame(ibuf, cbuf + 1, 3);
+               /* Now add the SOF markers */
+               cbuf[0] = GSM1_SOF;
+               cbuf[len + 1] = GSM1_SOF;
+               /* FIXME: we can omit the lead one in many cases */
+               len += 2;
+               break;
+       default:
+               WARN_ON(1);
+               return;
+       }
+       gsm->output(gsm, cbuf, len);
+       gsm_print_packet("-->", addr, cr, control, NULL, 0);
+}
+
+/**
+ *     gsm_response    -       send a control response
+ *     @gsm: our GSM mux
+ *     @addr: address for control frame
+ *     @control:  control byte including PF bit
+ *
+ *     Format up and transmit a link level response frame.
+ */
+
+static inline void gsm_response(struct gsm_mux *gsm, int addr, int control)
+{
+       gsm_send(gsm, addr, 0, control);
+}
+
+/**
+ *     gsm_command     -       send a control command
+ *     @gsm: our GSM mux
+ *     @addr: address for control frame
+ *     @control:  control byte including PF bit
+ *
+ *     Format up and transmit a link level command frame.
+ */
+
+static inline void gsm_command(struct gsm_mux *gsm, int addr, int control)
+{
+       gsm_send(gsm, addr, 1, control);
+}
+
+/* Data transmission */
+
+#define HDR_LEN                6       /* ADDR CTRL [LEN.2] DATA FCS */
+
+/**
+ *     gsm_data_alloc          -       allocate data frame
+ *     @gsm: GSM mux
+ *     @addr: DLCI address
+ *     @len: length excluding header and FCS
+ *     @ctrl: control byte
+ *
+ *     Allocate a new data buffer for sending frames with data. Space is left
+ *     at the front for header bytes but that is treated as an implementation
+ *     detail and not for the high level code to use
+ */
+
+static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
+                                                               u8 ctrl)
+{
+       struct gsm_msg *m = kmalloc(sizeof(struct gsm_msg) + len + HDR_LEN,
+                                                               GFP_ATOMIC);
+       if (m == NULL)
+               return NULL;
+       m->data = m->buffer + HDR_LEN - 1;      /* Allow for FCS */
+       m->len = len;
+       m->addr = addr;
+       m->ctrl = ctrl;
+       m->next = NULL;
+       return m;
+}
+
+/**
+ *     gsm_data_kick           -       poke the queue
+ *     @gsm: GSM Mux
+ *
+ *     The tty device has called us to indicate that room has appeared in
+ *     the transmit queue. Ram more data into the pipe if we have any
+ *
+ *     FIXME: lock against link layer control transmissions
+ */
+
+static void gsm_data_kick(struct gsm_mux *gsm)
+{
+       struct gsm_msg *msg = gsm->tx_head;
+       int len;
+       int skip_sof = 0;
+
+       /* FIXME: We need to apply this solely to data messages */
+       if (gsm->constipated)
+               return;
+
+       while (gsm->tx_head != NULL) {
+               msg = gsm->tx_head;
+               if (gsm->encoding != 0) {
+                       gsm->txframe[0] = GSM1_SOF;
+                       len = gsm_stuff_frame(msg->data,
+                                               gsm->txframe + 1, msg->len);
+                       gsm->txframe[len + 1] = GSM1_SOF;
+                       len += 2;
+               } else {
+                       gsm->txframe[0] = GSM0_SOF;
+                       memcpy(gsm->txframe + 1 , msg->data, msg->len);
+                       gsm->txframe[msg->len + 1] = GSM0_SOF;
+                       len = msg->len + 2;
+               }
+
+               if (debug & 4) {
+                       printk("gsm_data_kick: \n");
+                       hex_packet(gsm->txframe, len);
+               }
+
+               if (gsm->output(gsm, gsm->txframe + skip_sof,
+                                               len - skip_sof) < 0)
+                       break;
+               /* FIXME: Can eliminate one SOF in many more cases */
+               gsm->tx_head = msg->next;
+               if (gsm->tx_head == NULL)
+                       gsm->tx_tail = NULL;
+               gsm->tx_bytes -= msg->len;
+               kfree(msg);
+               /* For a burst of frames skip the extra SOF within the
+                  burst */
+               skip_sof = 1;
+       }
+}
+
+/**
+ *     __gsm_data_queue                -       queue a UI or UIH frame
+ *     @dlci: DLCI sending the data
+ *     @msg: message queued
+ *
+ *     Add data to the transmit queue and try and get stuff moving
+ *     out of the mux tty if not already doing so. The Caller must hold
+ *     the gsm tx lock.
+ */
+
+static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
+{
+       struct gsm_mux *gsm = dlci->gsm;
+       u8 *dp = msg->data;
+       u8 *fcs = dp + msg->len;
+
+       /* Fill in the header */
+       if (gsm->encoding == 0) {
+               if (msg->len < 128)
+                       *--dp = (msg->len << 1) | EA;
+               else {
+                       *--dp = (msg->len >> 6) | EA;
+                       *--dp = (msg->len & 127) << 1;
+               }
+       }
+
+       *--dp = msg->ctrl;
+       if (gsm->initiator)
+               *--dp = (msg->addr << 2) | 2 | EA;
+       else
+               *--dp = (msg->addr << 2) | EA;
+       *fcs = gsm_fcs_add_block(INIT_FCS, dp , msg->data - dp);
+       /* Ugly protocol layering violation */
+       if (msg->ctrl == UI || msg->ctrl == (UI|PF))
+               *fcs = gsm_fcs_add_block(*fcs, msg->data, msg->len);
+       *fcs = 0xFF - *fcs;
+
+       gsm_print_packet("Q> ", msg->addr, gsm->initiator, msg->ctrl,
+                                                       msg->data, msg->len);
+
+       /* Move the header back and adjust the length, also allow for the FCS
+          now tacked on the end */
+       msg->len += (msg->data - dp) + 1;
+       msg->data = dp;
+
+       /* Add to the actual output queue */
+       if (gsm->tx_tail)
+               gsm->tx_tail->next = msg;
+       else
+               gsm->tx_head = msg;
+       gsm->tx_tail = msg;
+       gsm->tx_bytes += msg->len;
+       gsm_data_kick(gsm);
+}
+
+/**
+ *     gsm_data_queue          -       queue a UI or UIH frame
+ *     @dlci: DLCI sending the data
+ *     @msg: message queued
+ *
+ *     Add data to the transmit queue and try and get stuff moving
+ *     out of the mux tty if not already doing so. Take the
+ *     the gsm tx lock and dlci lock.
+ */
+
+static void gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
+       __gsm_data_queue(dlci, msg);
+       spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
+}
+
+/**
+ *     gsm_dlci_data_output    -       try and push data out of a DLCI
+ *     @gsm: mux
+ *     @dlci: the DLCI to pull data from
+ *
+ *     Pull data from a DLCI and send it into the transmit queue if there
+ *     is data. Keep to the MRU of the mux. This path handles the usual tty
+ *     interface which is a byte stream with optional modem data.
+ *
+ *     Caller must hold the tx_lock of the mux.
+ */
+
+static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
+{
+       struct gsm_msg *msg;
+       u8 *dp;
+       int len, size;
+       int h = dlci->adaption - 1;
+
+       len = kfifo_len(dlci->fifo);
+       if (len == 0)
+               return 0;
+
+       /* MTU/MRU count only the data bits */
+       if (len > gsm->mtu)
+               len = gsm->mtu;
+
+       size = len + h;
+
+       msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
+       /* FIXME: need a timer or something to kick this so it can't
+          get stuck with no work outstanding and no buffer free */
+       if (msg == NULL)
+               return -ENOMEM;
+       dp = msg->data;
+       switch (dlci->adaption) {
+       case 1: /* Unstructured */
+               break;
+       case 2: /* Unstructed with modem bits. Always one byte as we never
+                  send inline break data */
+               *dp += gsm_encode_modem(dlci);
+               len--;
+               break;
+       }
+       WARN_ON(kfifo_out_locked(dlci->fifo, dp , len, &dlci->lock) != len);
+       __gsm_data_queue(dlci, msg);
+       /* Bytes of data we used up */
+       return size;
+}
+
+/**
+ *     gsm_dlci_data_output_framed  -  try and push data out of a DLCI
+ *     @gsm: mux
+ *     @dlci: the DLCI to pull data from
+ *
+ *     Pull data from a DLCI and send it into the transmit queue if there
+ *     is data. Keep to the MRU of the mux. This path handles framed data
+ *     queued as skbuffs to the DLCI.
+ *
+ *     Caller must hold the tx_lock of the mux.
+ */
+
+static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
+                                               struct gsm_dlci *dlci)
+{
+       struct gsm_msg *msg;
+       u8 *dp;
+       int len, size;
+       int last = 0, first = 0;
+       int overhead = 0;
+
+       /* One byte per frame is used for B/F flags */
+       if (dlci->adaption == 4)
+               overhead = 1;
+
+       /* dlci->skb is locked by tx_lock */
+       if (dlci->skb == NULL) {
+               dlci->skb = skb_dequeue(&dlci->skb_list);
+               if (dlci->skb == NULL)
+                       return 0;
+               first = 1;
+       }
+       len = dlci->skb->len + overhead;
+
+       /* MTU/MRU count only the data bits */
+       if (len > gsm->mtu) {
+               if (dlci->adaption == 3) {
+                       /* Over long frame, bin it */
+                       kfree_skb(dlci->skb);
+                       dlci->skb = NULL;
+                       return 0;
+               }
+               len = gsm->mtu;
+       } else
+               last = 1;
+
+       size = len + overhead;
+       msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
+
+       /* FIXME: need a timer or something to kick this so it can't
+          get stuck with no work outstanding and no buffer free */
+       if (msg == NULL)
+               return -ENOMEM;
+       dp = msg->data;
+
+       if (dlci->adaption == 4) { /* Interruptible framed (Packetised Data) */
+               /* Flag byte to carry the start/end info */
+               *dp++ = last << 7 | first << 6 | 1;     /* EA */
+               len--;
+       }
+       memcpy(dp, skb_pull(dlci->skb, len), len);
+       __gsm_data_queue(dlci, msg);
+       if (last)
+               dlci->skb = NULL;
+       return size;
+}
+
+/**
+ *     gsm_dlci_data_sweep             -       look for data to send
+ *     @gsm: the GSM mux
+ *
+ *     Sweep the GSM mux channels in priority order looking for ones with
+ *     data to send. We could do with optimising this scan a bit. We aim
+ *     to fill the queue totally or up to TX_THRESH_HI bytes. Once we hit
+ *     TX_THRESH_LO we get called again
+ *
+ *     FIXME: We should round robin between groups and in theory you can
+ *     renegotiate DLCI priorities with optional stuff. Needs optimising.
+ */
+
+static void gsm_dlci_data_sweep(struct gsm_mux *gsm)
+{
+       int len;
+       /* Priority ordering: We should do priority with RR of the groups */
+       int i = 1;
+
+       while (i < NUM_DLCI) {
+               struct gsm_dlci *dlci;
+
+               if (gsm->tx_bytes > TX_THRESH_HI)
+                       break;
+               dlci = gsm->dlci[i];
+               if (dlci == NULL || dlci->constipated) {
+                       i++;
+                       continue;
+               }
+               if (dlci->adaption < 3)
+                       len = gsm_dlci_data_output(gsm, dlci);
+               else
+                       len = gsm_dlci_data_output_framed(gsm, dlci);
+               if (len < 0)
+                       break;
+               /* DLCI empty - try the next */
+               if (len == 0)
+                       i++;
+       }
+}
+
+/**
+ *     gsm_dlci_data_kick      -       transmit if possible
+ *     @dlci: DLCI to kick
+ *
+ *     Transmit data from this DLCI if the queue is empty. We can't rely on
+ *     a tty wakeup except when we filled the pipe so we need to fire off
+ *     new data ourselves in other cases.
+ */
+
+static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
+       /* If we have nothing running then we need to fire up */
+       if (dlci->gsm->tx_bytes == 0)
+               gsm_dlci_data_output(dlci->gsm, dlci);
+       else if (dlci->gsm->tx_bytes < TX_THRESH_LO)
+               gsm_dlci_data_sweep(dlci->gsm);
+       spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
+}
+
+/*
+ *     Control message processing
+ */
+
+
+/**
+ *     gsm_control_reply       -       send a response frame to a control
+ *     @gsm: gsm channel
+ *     @cmd: the command to use
+ *     @data: data to follow encoded info
+ *     @dlen: length of data
+ *
+ *     Encode up and queue a UI/UIH frame containing our response.
+ */
+
+static void gsm_control_reply(struct gsm_mux *gsm, int cmd, u8 *data,
+                                       int dlen)
+{
+       struct gsm_msg *msg;
+       msg = gsm_data_alloc(gsm, 0, dlen + 2, gsm->ftype);
+       msg->data[0] = (cmd & 0xFE) << 1 | EA;  /* Clear C/R */
+       msg->data[1] = (dlen << 1) | EA;
+       memcpy(msg->data + 2, data, dlen);
+       gsm_data_queue(gsm->dlci[0], msg);
+}
+
+/**
+ *     gsm_process_modem       -       process received modem status
+ *     @tty: virtual tty bound to the DLCI
+ *     @dlci: DLCI to affect
+ *     @modem: modem bits (full EA)
+ *
+ *     Used when a modem control message or line state inline in adaption
+ *     layer 2 is processed. Sort out the local modem state and throttles
+ */
+
+static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
+                                                       u32 modem)
+{
+       int  mlines = 0;
+       u8 brk = modem >> 6;
+
+       /* Flow control/ready to communicate */
+       if (modem & MDM_FC) {
+               /* Need to throttle our output on this device */
+               dlci->constipated = 1;
+       }
+       if (modem & MDM_RTC) {
+               mlines |= TIOCM_DSR | TIOCM_DTR;
+               dlci->constipated = 0;
+               gsm_dlci_data_kick(dlci);
+       }
+       /* Map modem bits */
+       if (modem & MDM_RTR)
+               mlines |= TIOCM_RTS | TIOCM_CTS;
+       if (modem & MDM_IC)
+               mlines |= TIOCM_RI;
+       if (modem & MDM_DV)
+               mlines |= TIOCM_CD;
+
+       /* Carrier drop -> hangup */
+       if (tty) {
+               if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD))
+                       if (!(tty->termios->c_cflag & CLOCAL))
+                               tty_hangup(tty);
+               if (brk & 0x01)
+                       tty_insert_flip_char(tty, 0, TTY_BREAK);
+       }
+       dlci->modem_rx = mlines;
+}
+
+/**
+ *     gsm_control_modem       -       modem status received
+ *     @gsm: GSM channel
+ *     @data: data following command
+ *     @clen: command length
+ *
+ *     We have received a modem status control message. This is used by
+ *     the GSM mux protocol to pass virtual modem line status and optionally
+ *     to indicate break signals. Unpack it, convert to Linux representation
+ *     and if need be stuff a break message down the tty.
+ */
+
+static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
+{
+       unsigned int addr = 0;
+       unsigned int modem = 0;
+       struct gsm_dlci *dlci;
+       int len = clen;
+       u8 *dp = data;
+       struct tty_struct *tty;
+
+       while (gsm_read_ea(&addr, *dp++) == 0) {
+               len--;
+               if (len == 0)
+                       return;
+       }
+       /* Must be at least one byte following the EA */
+       len--;
+       if (len <= 0)
+               return;
+
+       addr >>= 1;
+       /* Closed port, or invalid ? */
+       if (addr == 0 || addr >= NUM_DLCI || gsm->dlci[addr] == NULL)
+               return;
+       dlci = gsm->dlci[addr];
+
+       while (gsm_read_ea(&modem, *dp++) == 0) {
+               len--;
+               if (len == 0)
+                       return;
+       }
+       tty = tty_port_tty_get(&dlci->port);
+       gsm_process_modem(tty, dlci, modem);
+       if (tty) {
+               tty_wakeup(tty);
+               tty_kref_put(tty);
+       }
+       gsm_control_reply(gsm, CMD_MSC, data, clen);
+}
+
+/**
+ *     gsm_control_rls         -       remote line status
+ *     @gsm: GSM channel
+ *     @data: data bytes
+ *     @clen: data length
+ *
+ *     The modem sends us a two byte message on the control channel whenever
+ *     it wishes to send us an error state from the virtual link. Stuff
+ *     this into the uplink tty if present
+ */
+
+static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen)
+{
+       struct tty_struct *tty;
+       unsigned int addr = 0 ;
+       u8 bits;
+       int len = clen;
+       u8 *dp = data;
+
+       while (gsm_read_ea(&addr, *dp++) == 0) {
+               len--;
+               if (len == 0)
+                       return;
+       }
+       /* Must be at least one byte following ea */
+       len--;
+       if (len <= 0)
+               return;
+       addr >>= 1;
+       /* Closed port, or invalid ? */
+       if (addr == 0 || addr >= NUM_DLCI || gsm->dlci[addr] == NULL)
+               return;
+       /* No error ? */
+       bits = *dp;
+       if ((bits & 1) == 0)
+               return;
+       /* See if we have an uplink tty */
+       tty = tty_port_tty_get(&gsm->dlci[addr]->port);
+
+       if (tty) {
+               if (bits & 2)
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+               if (bits & 4)
+                       tty_insert_flip_char(tty, 0, TTY_PARITY);
+               if (bits & 8)
+                       tty_insert_flip_char(tty, 0, TTY_FRAME);
+               tty_flip_buffer_push(tty);
+               tty_kref_put(tty);
+       }
+       gsm_control_reply(gsm, CMD_RLS, data, clen);
+}
+
+static void gsm_dlci_begin_close(struct gsm_dlci *dlci);
+
+/**
+ *     gsm_control_message     -       DLCI 0 control processing
+ *     @gsm: our GSM mux
+ *     @command:  the command EA
+ *     @data: data beyond the command/length EAs
+ *     @clen: length
+ *
+ *     Input processor for control messages from the other end of the link.
+ *     Processes the incoming request and queues a response frame or an
+ *     NSC response if not supported
+ */
+
+static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
+                                                       u8 *data, int clen)
+{
+       u8 buf[1];
+       switch (command) {
+       case CMD_CLD: {
+               struct gsm_dlci *dlci = gsm->dlci[0];
+               /* Modem wishes to close down */
+               if (dlci) {
+                       dlci->dead = 1;
+                       gsm->dead = 1;
+                       gsm_dlci_begin_close(dlci);
+               }
+               }
+               break;
+       case CMD_TEST:
+               /* Modem wishes to test, reply with the data */
+               gsm_control_reply(gsm, CMD_TEST, data, clen);
+               break;
+       case CMD_FCON:
+               /* Modem wants us to STFU */
+               gsm->constipated = 1;
+               gsm_control_reply(gsm, CMD_FCON, NULL, 0);
+               break;
+       case CMD_FCOFF:
+               /* Modem can accept data again */
+               gsm->constipated = 0;
+               gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
+               /* Kick the link in case it is idling */
+               gsm_data_kick(gsm);
+               break;
+       case CMD_MSC:
+               /* Out of band modem line change indicator for a DLCI */
+               gsm_control_modem(gsm, data, clen);
+               break;
+       case CMD_RLS:
+               /* Out of band error reception for a DLCI */
+               gsm_control_rls(gsm, data, clen);
+               break;
+       case CMD_PSC:
+               /* Modem wishes to enter power saving state */
+               gsm_control_reply(gsm, CMD_PSC, NULL, 0);
+               break;
+               /* Optional unsupported commands */
+       case CMD_PN:    /* Parameter negotiation */
+       case CMD_RPN:   /* Remote port negotation */
+       case CMD_SNC:   /* Service negotation command */
+       default:
+               /* Reply to bad commands with an NSC */
+               buf[0] = command;
+               gsm_control_reply(gsm, CMD_NSC, buf, 1);
+               break;
+       }
+}
+
+/**
+ *     gsm_control_response    -       process a response to our control
+ *     @gsm: our GSM mux
+ *     @command: the command (response) EA
+ *     @data: data beyond the command/length EA
+ *     @clen: length
+ *
+ *     Process a response to an outstanding command. We only allow a single
+ *     control message in flight so this is fairly easy. All the clean up
+ *     is done by the caller, we just update the fields, flag it as done
+ *     and return
+ */
+
+static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
+                                                       u8 *data, int clen)
+{
+       struct gsm_control *ctrl;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gsm->control_lock, flags);
+
+       ctrl = gsm->pending_cmd;
+       /* Does the reply match our command */
+       command |= 1;
+       if (ctrl != NULL && (command == ctrl->cmd || command == CMD_NSC)) {
+               /* Our command was replied to, kill the retry timer */
+               del_timer(&gsm->t2_timer);
+               gsm->pending_cmd = NULL;
+               /* Rejected by the other end */
+               if (command == CMD_NSC)
+                       ctrl->error = -EOPNOTSUPP;
+               ctrl->done = 1;
+               wake_up(&gsm->event);
+       }
+       spin_unlock_irqrestore(&gsm->control_lock, flags);
+}
+
+/**
+ *     gsm_control_transmit    -       send control packet
+ *     @gsm: gsm mux
+ *     @ctrl: frame to send
+ *
+ *     Send out a pending control command (called under control lock)
+ */
+
+static void gsm_control_transmit(struct gsm_mux *gsm, struct gsm_control *ctrl)
+{
+       struct gsm_msg *msg = gsm_data_alloc(gsm, 0, ctrl->len + 1,
+                                                       gsm->ftype|PF);
+       if (msg == NULL)
+               return;
+       msg->data[0] = (ctrl->cmd << 1) | 2 | EA;       /* command */
+       memcpy(msg->data + 1, ctrl->data, ctrl->len);
+       gsm_data_queue(gsm->dlci[0], msg);
+}
+
+/**
+ *     gsm_control_retransmit  -       retransmit a control frame
+ *     @data: pointer to our gsm object
+ *
+ *     Called off the T2 timer expiry in order to retransmit control frames
+ *     that have been lost in the system somewhere. The control_lock protects
+ *     us from colliding with another sender or a receive completion event.
+ *     In that situation the timer may still occur in a small window but
+ *     gsm->pending_cmd will be NULL and we just let the timer expire.
+ */
+
+static void gsm_control_retransmit(unsigned long data)
+{
+       struct gsm_mux *gsm = (struct gsm_mux *)data;
+       struct gsm_control *ctrl;
+       unsigned long flags;
+       spin_lock_irqsave(&gsm->control_lock, flags);
+       ctrl = gsm->pending_cmd;
+       if (ctrl) {
+               gsm->cretries--;
+               if (gsm->cretries == 0) {
+                       gsm->pending_cmd = NULL;
+                       ctrl->error = -ETIMEDOUT;
+                       ctrl->done = 1;
+                       spin_unlock_irqrestore(&gsm->control_lock, flags);
+                       wake_up(&gsm->event);
+                       return;
+               }
+               gsm_control_transmit(gsm, ctrl);
+               mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
+       }
+       spin_unlock_irqrestore(&gsm->control_lock, flags);
+}
+
+/**
+ *     gsm_control_send        -       send a control frame on DLCI 0
+ *     @gsm: the GSM channel
+ *     @command: command  to send including CR bit
+ *     @data: bytes of data (must be kmalloced)
+ *     @len: length of the block to send
+ *
+ *     Queue and dispatch a control command. Only one command can be
+ *     active at a time. In theory more can be outstanding but the matching
+ *     gets really complicated so for now stick to one outstanding.
+ */
+
+static struct gsm_control *gsm_control_send(struct gsm_mux *gsm,
+               unsigned int command, u8 *data, int clen)
+{
+       struct gsm_control *ctrl = kzalloc(sizeof(struct gsm_control),
+                                               GFP_KERNEL);
+       unsigned long flags;
+       if (ctrl == NULL)
+               return NULL;
+retry:
+       wait_event(gsm->event, gsm->pending_cmd == NULL);
+       spin_lock_irqsave(&gsm->control_lock, flags);
+       if (gsm->pending_cmd != NULL) {
+               spin_unlock_irqrestore(&gsm->control_lock, flags);
+               goto retry;
+       }
+       ctrl->cmd = command;
+       ctrl->data = data;
+       ctrl->len = clen;
+       gsm->pending_cmd = ctrl;
+       gsm->cretries = gsm->n2;
+       mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
+       gsm_control_transmit(gsm, ctrl);
+       spin_unlock_irqrestore(&gsm->control_lock, flags);
+       return ctrl;
+}
+
+/**
+ *     gsm_control_wait        -       wait for a control to finish
+ *     @gsm: GSM mux
+ *     @control: control we are waiting on
+ *
+ *     Waits for the control to complete or time out. Frees any used
+ *     resources and returns 0 for success, or an error if the remote
+ *     rejected or ignored the request.
+ */
+
+static int gsm_control_wait(struct gsm_mux *gsm, struct gsm_control *control)
+{
+       int err;
+       wait_event(gsm->event, control->done == 1);
+       err = control->error;
+       kfree(control);
+       return err;
+}
+
+
+/*
+ *     DLCI level handling: Needs krefs
+ */
+
+/*
+ *     State transitions and timers
+ */
+
+/**
+ *     gsm_dlci_close          -       a DLCI has closed
+ *     @dlci: DLCI that closed
+ *
+ *     Perform processing when moving a DLCI into closed state. If there
+ *     is an attached tty this is hung up
+ */
+
+static void gsm_dlci_close(struct gsm_dlci *dlci)
+{
+       del_timer(&dlci->t1);
+       if (debug & 8)
+               printk("DLCI %d goes closed.\n", dlci->addr);
+       dlci->state = DLCI_CLOSED;
+       if (dlci->addr != 0) {
+               struct tty_struct  *tty = tty_port_tty_get(&dlci->port);
+               if (tty) {
+                       tty_hangup(tty);
+                       tty_kref_put(tty);
+               }
+               kfifo_reset(dlci->fifo);
+       } else
+               dlci->gsm->dead = 1;
+       wake_up(&dlci->gsm->event);
+       /* A DLCI 0 close is a MUX termination so we need to kick that
+          back to userspace somehow */
+}
+
+/**
+ *     gsm_dlci_open           -       a DLCI has opened
+ *     @dlci: DLCI that opened
+ *
+ *     Perform processing when moving a DLCI into open state.
+ */
+
+static void gsm_dlci_open(struct gsm_dlci *dlci)
+{
+       /* Note that SABM UA .. SABM UA first UA lost can mean that we go
+          open -> open */
+       del_timer(&dlci->t1);
+       /* This will let a tty open continue */
+       dlci->state = DLCI_OPEN;
+       if (debug & 8)
+               printk("DLCI %d goes open.\n", dlci->addr);
+       wake_up(&dlci->gsm->event);
+}
+
+/**
+ *     gsm_dlci_t1             -       T1 timer expiry
+ *     @dlci: DLCI that opened
+ *
+ *     The T1 timer handles retransmits of control frames (essentially of
+ *     SABM and DISC). We resend the command until the retry count runs out
+ *     in which case an opening port goes back to closed and a closing port
+ *     is simply put into closed state (any further frames from the other
+ *     end will get a DM response)
+ */
+
+static void gsm_dlci_t1(unsigned long data)
+{
+       struct gsm_dlci *dlci = (struct gsm_dlci *)data;
+       struct gsm_mux *gsm = dlci->gsm;
+
+       switch (dlci->state) {
+       case DLCI_OPENING:
+               dlci->retries--;
+               if (dlci->retries) {
+                       gsm_command(dlci->gsm, dlci->addr, SABM|PF);
+                       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
+               } else
+                       gsm_dlci_close(dlci);
+               break;
+       case DLCI_CLOSING:
+               dlci->retries--;
+               if (dlci->retries) {
+                       gsm_command(dlci->gsm, dlci->addr, DISC|PF);
+                       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
+               } else
+                       gsm_dlci_close(dlci);
+               break;
+       }
+}
+
+/**
+ *     gsm_dlci_begin_open     -       start channel open procedure
+ *     @dlci: DLCI to open
+ *
+ *     Commence opening a DLCI from the Linux side. We issue SABM messages
+ *     to the modem which should then reply with a UA, at which point we
+ *     will move into open state. Opening is done asynchronously with retry
+ *     running off timers and the responses.
+ */
+
+static void gsm_dlci_begin_open(struct gsm_dlci *dlci)
+{
+       struct gsm_mux *gsm = dlci->gsm;
+       if (dlci->state == DLCI_OPEN || dlci->state == DLCI_OPENING)
+               return;
+       dlci->retries = gsm->n2;
+       dlci->state = DLCI_OPENING;
+       gsm_command(dlci->gsm, dlci->addr, SABM|PF);
+       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
+}
+
+/**
+ *     gsm_dlci_begin_close    -       start channel open procedure
+ *     @dlci: DLCI to open
+ *
+ *     Commence closing a DLCI from the Linux side. We issue DISC messages
+ *     to the modem which should then reply with a UA, at which point we
+ *     will move into closed state. Closing is done asynchronously with retry
+ *     off timers. We may also receive a DM reply from the other end which
+ *     indicates the channel was already closed.
+ */
+
+static void gsm_dlci_begin_close(struct gsm_dlci *dlci)
+{
+       struct gsm_mux *gsm = dlci->gsm;
+       if (dlci->state == DLCI_CLOSED || dlci->state == DLCI_CLOSING)
+               return;
+       dlci->retries = gsm->n2;
+       dlci->state = DLCI_CLOSING;
+       gsm_command(dlci->gsm, dlci->addr, DISC|PF);
+       mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
+}
+
+/**
+ *     gsm_dlci_data           -       data arrived
+ *     @dlci: channel
+ *     @data: block of bytes received
+ *     @len: length of received block
+ *
+ *     A UI or UIH frame has arrived which contains data for a channel
+ *     other than the control channel. If the relevant virtual tty is
+ *     open we shovel the bits down it, if not we drop them.
+ */
+
+static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int len)
+{
+       /* krefs .. */
+       struct tty_port *port = &dlci->port;
+       struct tty_struct *tty = tty_port_tty_get(port);
+       unsigned int modem = 0;
+
+       if (debug & 16)
+               printk("%d bytes for tty %p\n", len, tty);
+       if (tty) {
+               switch (dlci->adaption)  {
+                       /* Unsupported types */
+                       /* Packetised interruptible data */
+                       case 4:
+                               break;
+                       /* Packetised uininterruptible voice/data */
+                       case 3:
+                               break;
+                       /* Asynchronous serial with line state in each frame */
+                       case 2:
+                               while (gsm_read_ea(&modem, *data++) == 0) {
+                                       len--;
+                                       if (len == 0)
+                                               return;
+                               }
+                               gsm_process_modem(tty, dlci, modem);
+                       /* Line state will go via DLCI 0 controls only */
+                       case 1:
+                       default:
+                               tty_insert_flip_string(tty, data, len);
+                               tty_flip_buffer_push(tty);
+               }
+               tty_kref_put(tty);
+       }
+}
+
+/**
+ *     gsm_dlci_control        -       data arrived on control channel
+ *     @dlci: channel
+ *     @data: block of bytes received
+ *     @len: length of received block
+ *
+ *     A UI or UIH frame has arrived which contains data for DLCI 0 the
+ *     control channel. This should contain a command EA followed by
+ *     control data bytes. The command EA contains a command/response bit
+ *     and we divide up the work accordingly.
+ */
+
+static void gsm_dlci_command(struct gsm_dlci *dlci, u8 *data, int len)
+{
+       /* See what command is involved */
+       unsigned int command = 0;
+       while (len-- > 0) {
+               if (gsm_read_ea(&command, *data++) == 1) {
+                       int clen = *data++;
+                       len--;
+                       /* FIXME: this is properly an EA */
+                       clen >>= 1;
+                       /* Malformed command ? */
+                       if (clen > len)
+                               return;
+                       if (command & 1)
+                               gsm_control_message(dlci->gsm, command,
+                                                               data, clen);
+                       else
+                               gsm_control_response(dlci->gsm, command,
+                                                               data, clen);
+                       return;
+               }
+       }
+}
+
+/*
+ *     Allocate/Free DLCI channels
+ */
+
+/**
+ *     gsm_dlci_alloc          -       allocate a DLCI
+ *     @gsm: GSM mux
+ *     @addr: address of the DLCI
+ *
+ *     Allocate and install a new DLCI object into the GSM mux.
+ *
+ *     FIXME: review locking races
+ */
+
+static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
+{
+       struct gsm_dlci *dlci = kzalloc(sizeof(struct gsm_dlci), GFP_ATOMIC);
+       if (dlci == NULL)
+               return NULL;
+       spin_lock_init(&dlci->lock);
+       dlci->fifo = &dlci->_fifo;
+       if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) {
+               kfree(dlci);
+               return NULL;
+       }
+
+       skb_queue_head_init(&dlci->skb_list);
+       init_timer(&dlci->t1);
+       dlci->t1.function = gsm_dlci_t1;
+       dlci->t1.data = (unsigned long)dlci;
+       tty_port_init(&dlci->port);
+       dlci->port.ops = &gsm_port_ops;
+       dlci->gsm = gsm;
+       dlci->addr = addr;
+       dlci->adaption = gsm->adaption;
+       dlci->state = DLCI_CLOSED;
+       if (addr)
+               dlci->data = gsm_dlci_data;
+       else
+               dlci->data = gsm_dlci_command;
+       gsm->dlci[addr] = dlci;
+       return dlci;
+}
+
+/**
+ *     gsm_dlci_free           -       release DLCI
+ *     @dlci: DLCI to destroy
+ *
+ *     Free up a DLCI. Currently to keep the lifetime rules sane we only
+ *     clean up DLCI objects when the MUX closes rather than as the port
+ *     is closed down on both the tty and mux levels.
+ *
+ *     Can sleep.
+ */
+static void gsm_dlci_free(struct gsm_dlci *dlci)
+{
+       struct tty_struct *tty = tty_port_tty_get(&dlci->port);
+       if (tty) {
+               tty_vhangup(tty);
+               tty_kref_put(tty);
+       }
+       del_timer_sync(&dlci->t1);
+       dlci->gsm->dlci[dlci->addr] = NULL;
+       kfifo_free(dlci->fifo);
+       kfree(dlci);
+}
+
+
+/*
+ *     LAPBish link layer logic
+ */
+
+/**
+ *     gsm_queue               -       a GSM frame is ready to process
+ *     @gsm: pointer to our gsm mux
+ *
+ *     At this point in time a frame has arrived and been demangled from
+ *     the line encoding. All the differences between the encodings have
+ *     been handled below us and the frame is unpacked into the structures.
+ *     The fcs holds the header FCS but any data FCS must be added here.
+ */
+
+static void gsm_queue(struct gsm_mux *gsm)
+{
+       struct gsm_dlci *dlci;
+       u8 cr;
+       int address;
+       /* We have to sneak a look at the packet body to do the FCS.
+          A somewhat layering violation in the spec */
+
+       if ((gsm->control & ~PF) == UI)
+               gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len);
+       if (gsm->fcs != GOOD_FCS) {
+               gsm->bad_fcs++;
+               if (debug & 4)
+                       printk("BAD FCS %02x\n", gsm->fcs);
+               return;
+       }
+       address = gsm->address >> 1;
+       if (address >= NUM_DLCI)
+               goto invalid;
+
+       cr = gsm->address & 1;          /* C/R bit */
+
+       gsm_print_packet("<--", address, cr, gsm->control, gsm->buf, gsm->len);
+
+       cr ^= 1 - gsm->initiator;       /* Flip so 1 always means command */
+       dlci = gsm->dlci[address];
+
+       switch (gsm->control) {
+       case SABM|PF:
+               if (cr == 0)
+                       goto invalid;
+               if (dlci == NULL)
+                       dlci = gsm_dlci_alloc(gsm, address);
+               if (dlci == NULL)
+                       return;
+               if (dlci->dead)
+                       gsm_response(gsm, address, DM);
+               else {
+                       gsm_response(gsm, address, UA);
+                       gsm_dlci_open(dlci);
+               }
+               break;
+       case DISC|PF:
+               if (cr == 0)
+                       goto invalid;
+               if (dlci == NULL || dlci->state == DLCI_CLOSED) {
+                       gsm_response(gsm, address, DM);
+                       return;
+               }
+               /* Real close complete */
+               gsm_response(gsm, address, UA);
+               gsm_dlci_close(dlci);
+               break;
+       case UA:
+       case UA|PF:
+               if (cr == 0 || dlci == NULL)
+                       break;
+               switch (dlci->state) {
+               case DLCI_CLOSING:
+                       gsm_dlci_close(dlci);
+                       break;
+               case DLCI_OPENING:
+                       gsm_dlci_open(dlci);
+                       break;
+               }
+               break;
+       case DM:        /* DM can be valid unsolicited */
+       case DM|PF:
+               if (cr)
+                       goto invalid;
+               if (dlci == NULL)
+                       return;
+               gsm_dlci_close(dlci);
+               break;
+       case UI:
+       case UI|PF:
+       case UIH:
+       case UIH|PF:
+#if 0
+               if (cr)
+                       goto invalid;
+#endif
+               if (dlci == NULL || dlci->state != DLCI_OPEN) {
+                       gsm_command(gsm, address, DM|PF);
+                       return;
+               }
+               dlci->data(dlci, gsm->buf, gsm->len);
+               break;
+       default:
+               goto invalid;
+       }
+       return;
+invalid:
+       gsm->malformed++;
+       return;
+}
+
+
+/**
+ *     gsm0_receive    -       perform processing for non-transparency
+ *     @gsm: gsm data for this ldisc instance
+ *     @c: character
+ *
+ *     Receive bytes in gsm mode 0
+ */
+
+static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
+{
+       switch (gsm->state) {
+       case GSM_SEARCH:        /* SOF marker */
+               if (c == GSM0_SOF) {
+                       gsm->state = GSM_ADDRESS;
+                       gsm->address = 0;
+                       gsm->len = 0;
+                       gsm->fcs = INIT_FCS;
+               }
+               break;          /* Address EA */
+       case GSM_ADDRESS:
+               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+               if (gsm_read_ea(&gsm->address, c))
+                       gsm->state = GSM_CONTROL;
+               break;
+       case GSM_CONTROL:       /* Control Byte */
+               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+               gsm->control = c;
+               gsm->state = GSM_LEN;
+               break;
+       case GSM_LEN:           /* Length EA */
+               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+               if (gsm_read_ea(&gsm->len, c)) {
+                       if (gsm->len > gsm->mru) {
+                               gsm->bad_size++;
+                               gsm->state = GSM_SEARCH;
+                               break;
+                       }
+                       gsm->count = 0;
+                       gsm->state = GSM_DATA;
+               }
+               break;
+       case GSM_DATA:          /* Data */
+               gsm->buf[gsm->count++] = c;
+               if (gsm->count == gsm->len)
+                       gsm->state = GSM_FCS;
+               break;
+       case GSM_FCS:           /* FCS follows the packet */
+               gsm->fcs = c;
+               gsm_queue(gsm);
+               /* And then back for the next frame */
+               gsm->state = GSM_SEARCH;
+               break;
+       }
+}
+
+/**
+ *     gsm0_receive    -       perform processing for non-transparency
+ *     @gsm: gsm data for this ldisc instance
+ *     @c: character
+ *
+ *     Receive bytes in mode 1 (Advanced option)
+ */
+
+static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
+{
+       if (c == GSM1_SOF) {
+               /* EOF is only valid in frame if we have got to the data state
+                  and received at least one byte (the FCS) */
+               if (gsm->state == GSM_DATA && gsm->count) {
+                       /* Extract the FCS */
+                       gsm->count--;
+                       gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->buf[gsm->count]);
+                       gsm->len = gsm->count;
+                       gsm_queue(gsm);
+                       gsm->state  = GSM_START;
+                       return;
+               }
+               /* Any partial frame was a runt so go back to start */
+               if (gsm->state != GSM_START) {
+                       gsm->malformed++;
+                       gsm->state = GSM_START;
+               }
+               /* A SOF in GSM_START means we are still reading idling or
+                  framing bytes */
+               return;
+       }
+
+       if (c == GSM1_ESCAPE) {
+               gsm->escape = 1;
+               return;
+       }
+
+       /* Only an unescaped SOF gets us out of GSM search */
+       if (gsm->state == GSM_SEARCH)
+               return;
+
+       if (gsm->escape) {
+               c ^= GSM1_ESCAPE_BITS;
+               gsm->escape = 0;
+       }
+       switch (gsm->state) {
+       case GSM_START:         /* First byte after SOF */
+               gsm->address = 0;
+               gsm->state = GSM_ADDRESS;
+               gsm->fcs = INIT_FCS;
+               /* Drop through */
+       case GSM_ADDRESS:       /* Address continuation */
+               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+               if (gsm_read_ea(&gsm->address, c))
+                       gsm->state = GSM_CONTROL;
+               break;
+       case GSM_CONTROL:       /* Control Byte */
+               gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+               gsm->control = c;
+               gsm->count = 0;
+               gsm->state = GSM_DATA;
+               break;
+       case GSM_DATA:          /* Data */
+               if (gsm->count > gsm->mru ) {   /* Allow one for the FCS */
+                       gsm->state = GSM_OVERRUN;
+                       gsm->bad_size++;
+               } else
+                       gsm->buf[gsm->count++] = c;
+               break;
+       case GSM_OVERRUN:       /* Over-long - eg a dropped SOF */
+               break;
+       }
+}
+
+/**
+ *     gsm_error               -       handle tty error
+ *     @gsm: ldisc data
+ *     @data: byte received (may be invalid)
+ *     @flag: error received
+ *
+ *     Handle an error in the receipt of data for a frame. Currently we just
+ *     go back to hunting for a SOF.
+ *
+ *     FIXME: better diagnostics ?
+ */
+
+static void gsm_error(struct gsm_mux *gsm,
+                               unsigned char data, unsigned char flag)
+{
+       gsm->state = GSM_SEARCH;
+       gsm->io_error++;
+}
+
+/**
+ *     gsm_cleanup_mux         -       generic GSM protocol cleanup
+ *     @gsm: our mux
+ *
+ *     Clean up the bits of the mux which are the same for all framing
+ *     protocols. Remove the mux from the mux table, stop all the timers
+ *     and then shut down each device hanging up the channels as we go.
+ */
+
+void gsm_cleanup_mux(struct gsm_mux *gsm)
+{
+       int i;
+       struct gsm_dlci *dlci = gsm->dlci[0];
+       struct gsm_msg *txq;
+
+       gsm->dead = 1;
+
+       spin_lock(&gsm_mux_lock);
+       for (i = 0; i < MAX_MUX; i++) {
+               if (gsm_mux[i] == gsm) {
+                       gsm_mux[i] = NULL;
+                       break;
+               }
+       }
+       spin_unlock(&gsm_mux_lock);
+       WARN_ON(i == MAX_MUX);
+
+       del_timer_sync(&gsm->t2_timer);
+       /* Now we are sure T2 has stopped */
+       if (dlci) {
+               dlci->dead = 1;
+               gsm_dlci_begin_close(dlci);
+               wait_event_interruptible(gsm->event,
+                                       dlci->state == DLCI_CLOSED);
+       }
+       /* Free up any link layer users */
+       for (i = 0; i < NUM_DLCI; i++)
+               if (gsm->dlci[i])
+                       gsm_dlci_free(gsm->dlci[i]);
+       /* Now wipe the queues */
+       for (txq = gsm->tx_head; txq != NULL; txq = gsm->tx_head) {
+               gsm->tx_head = txq->next;
+               kfree(txq);
+       }
+       gsm->tx_tail = NULL;
+}
+EXPORT_SYMBOL_GPL(gsm_cleanup_mux);
+
+/**
+ *     gsm_activate_mux        -       generic GSM setup
+ *     @gsm: our mux
+ *
+ *     Set up the bits of the mux which are the same for all framing
+ *     protocols. Add the mux to the mux table so it can be opened and
+ *     finally kick off connecting to DLCI 0 on the modem.
+ */
+
+int gsm_activate_mux(struct gsm_mux *gsm)
+{
+       struct gsm_dlci *dlci;
+       int i = 0;
+
+       init_timer(&gsm->t2_timer);
+       gsm->t2_timer.function = gsm_control_retransmit;
+       gsm->t2_timer.data = (unsigned long)gsm;
+       init_waitqueue_head(&gsm->event);
+       spin_lock_init(&gsm->control_lock);
+       spin_lock_init(&gsm->tx_lock);
+
+       if (gsm->encoding == 0)
+               gsm->receive = gsm0_receive;
+       else
+               gsm->receive = gsm1_receive;
+       gsm->error = gsm_error;
+
+       spin_lock(&gsm_mux_lock);
+       for (i = 0; i < MAX_MUX; i++) {
+               if (gsm_mux[i] == NULL) {
+                       gsm_mux[i] = gsm;
+                       break;
+               }
+       }
+       spin_unlock(&gsm_mux_lock);
+       if (i == MAX_MUX)
+               return -EBUSY;
+
+       dlci = gsm_dlci_alloc(gsm, 0);
+       if (dlci == NULL)
+               return -ENOMEM;
+       gsm->dead = 0;          /* Tty opens are now permissible */
+       return 0;
+}
+EXPORT_SYMBOL_GPL(gsm_activate_mux);
+
+/**
+ *     gsm_free_mux            -       free up a mux
+ *     @mux: mux to free
+ *
+ *     Dispose of allocated resources for a dead mux. No refcounting
+ *     at present so the mux must be truely dead.
+ */
+void gsm_free_mux(struct gsm_mux *gsm)
+{
+       kfree(gsm->txframe);
+       kfree(gsm->buf);
+       kfree(gsm);
+}
+EXPORT_SYMBOL_GPL(gsm_free_mux);
+
+/**
+ *     gsm_alloc_mux           -       allocate a mux
+ *
+ *     Creates a new mux ready for activation.
+ */
+
+struct gsm_mux *gsm_alloc_mux(void)
+{
+       struct gsm_mux *gsm = kzalloc(sizeof(struct gsm_mux), GFP_KERNEL);
+       if (gsm == NULL)
+               return NULL;
+       gsm->buf = kmalloc(MAX_MRU + 1, GFP_KERNEL);
+       if (gsm->buf == NULL) {
+               kfree(gsm);
+               return NULL;
+       }
+       gsm->txframe = kmalloc(2 * MAX_MRU + 2, GFP_KERNEL);
+       if (gsm->txframe == NULL) {
+               kfree(gsm->buf);
+               kfree(gsm);
+               return NULL;
+       }
+       spin_lock_init(&gsm->lock);
+
+       gsm->t1 = T1;
+       gsm->t2 = T2;
+       gsm->n2 = N2;
+       gsm->ftype = UIH;
+       gsm->initiator = 0;
+       gsm->adaption = 1;
+       gsm->encoding = 1;
+       gsm->mru = 64;  /* Default to encoding 1 so these should be 64 */
+       gsm->mtu = 64;
+       gsm->dead = 1;  /* Avoid early tty opens */
+
+       return gsm;
+}
+EXPORT_SYMBOL_GPL(gsm_alloc_mux);
+
+
+
+
+/**
+ *     gsmld_output            -       write to link
+ *     @gsm: our mux
+ *     @data: bytes to output
+ *     @len: size
+ *
+ *     Write a block of data from the GSM mux to the data channel. This
+ *     will eventually be serialized from above but at the moment isn't.
+ */
+
+static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len)
+{
+       if (tty_write_room(gsm->tty) < len) {
+               set_bit(TTY_DO_WRITE_WAKEUP, &gsm->tty->flags);
+               return -ENOSPC;
+       }
+       if (debug & 4) {
+               printk("-->%d bytes out\n", len);
+               hex_packet(data, len);
+       }
+       gsm->tty->ops->write(gsm->tty, data, len);
+       return len;
+}
+
+/**
+ *     gsmld_attach_gsm        -       mode set up
+ *     @tty: our tty structure
+ *     @gsm: our mux
+ *
+ *     Set up the MUX for basic mode and commence connecting to the
+ *     modem. Currently called from the line discipline set up but
+ *     will need moving to an ioctl path.
+ */
+
+static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
+{
+       int ret;
+
+       gsm->tty = tty_kref_get(tty);
+       gsm->output = gsmld_output;
+       ret =  gsm_activate_mux(gsm);
+       if (ret != 0)
+               tty_kref_put(gsm->tty);
+       return ret;
+}
+
+
+/**
+ *     gsmld_detach_gsm        -       stop doing 0710 mux
+ *     @tty: tty atttached to the mux
+ *     @gsm: mux
+ *
+ *     Shutdown and then clean up the resources used by the line discipline
+ */
+
+static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
+{
+       WARN_ON(tty != gsm->tty);
+       gsm_cleanup_mux(gsm);
+       tty_kref_put(gsm->tty);
+       gsm->tty = NULL;
+}
+
+static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                             char *fp, int count)
+{
+       struct gsm_mux *gsm = tty->disc_data;
+       const unsigned char *dp;
+       char *f;
+       int i;
+       char buf[64];
+       char flags;
+
+       if (debug & 4) {
+               printk("Inbytes %dd\n", count);
+               hex_packet(cp, count);
+       }
+
+       for (i = count, dp = cp, f = fp; i; i--, dp++) {
+               flags = *f++;
+               switch (flags) {
+               case TTY_NORMAL:
+                       gsm->receive(gsm, *dp);
+                       break;
+               case TTY_OVERRUN:
+               case TTY_BREAK:
+               case TTY_PARITY:
+               case TTY_FRAME:
+                       gsm->error(gsm, *dp, flags);
+                       break;
+               default:
+                       printk(KERN_ERR "%s: unknown flag %d\n",
+                              tty_name(tty, buf), flags);
+                       break;
+               }
+       }
+       /* FASYNC if needed ? */
+       /* If clogged call tty_throttle(tty); */
+}
+
+/**
+ *     gsmld_chars_in_buffer   -       report available bytes
+ *     @tty: tty device
+ *
+ *     Report the number of characters buffered to be delivered to user
+ *     at this instant in time.
+ *
+ *     Locking: gsm lock
+ */
+
+static ssize_t gsmld_chars_in_buffer(struct tty_struct *tty)
+{
+       return 0;
+}
+
+/**
+ *     gsmld_flush_buffer      -       clean input queue
+ *     @tty:   terminal device
+ *
+ *     Flush the input buffer. Called when the line discipline is
+ *     being closed, when the tty layer wants the buffer flushed (eg
+ *     at hangup).
+ */
+
+static void gsmld_flush_buffer(struct tty_struct *tty)
+{
+}
+
+/**
+ *     gsmld_close             -       close the ldisc for this tty
+ *     @tty: device
+ *
+ *     Called from the terminal layer when this line discipline is
+ *     being shut down, either because of a close or becsuse of a
+ *     discipline change. The function will not be called while other
+ *     ldisc methods are in progress.
+ */
+
+static void gsmld_close(struct tty_struct *tty)
+{
+       struct gsm_mux *gsm = tty->disc_data;
+
+       gsmld_detach_gsm(tty, gsm);
+
+       gsmld_flush_buffer(tty);
+       /* Do other clean up here */
+       gsm_free_mux(gsm);
+}
+
+/**
+ *     gsmld_open              -       open an ldisc
+ *     @tty: terminal to open
+ *
+ *     Called when this line discipline is being attached to the
+ *     terminal device. Can sleep. Called serialized so that no
+ *     other events will occur in parallel. No further open will occur
+ *     until a close.
+ */
+
+static int gsmld_open(struct tty_struct *tty)
+{
+       struct gsm_mux *gsm;
+
+       if (tty->ops->write == NULL)
+               return -EINVAL;
+
+       /* Attach our ldisc data */
+       gsm = gsm_alloc_mux();
+       if (gsm == NULL)
+               return -ENOMEM;
+
+       tty->disc_data = gsm;
+       tty->receive_room = 65536;
+
+       /* Attach the initial passive connection */
+       gsm->encoding = 1;
+       return gsmld_attach_gsm(tty, gsm);
+}
+
+/**
+ *     gsmld_write_wakeup      -       asynchronous I/O notifier
+ *     @tty: tty device
+ *
+ *     Required for the ptys, serial driver etc. since processes
+ *     that attach themselves to the master and rely on ASYNC
+ *     IO must be woken up
+ */
+
+static void gsmld_write_wakeup(struct tty_struct *tty)
+{
+       struct gsm_mux *gsm = tty->disc_data;
+       unsigned long flags;
+
+       /* Queue poll */
+       clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+       gsm_data_kick(gsm);
+       if (gsm->tx_bytes < TX_THRESH_LO) {
+               spin_lock_irqsave(&gsm->tx_lock, flags);
+               gsm_dlci_data_sweep(gsm);
+               spin_unlock_irqrestore(&gsm->tx_lock, flags);
+       }
+}
+
+/**
+ *     gsmld_read              -       read function for tty
+ *     @tty: tty device
+ *     @file: file object
+ *     @buf: userspace buffer pointer
+ *     @nr: size of I/O
+ *
+ *     Perform reads for the line discipline. We are guaranteed that the
+ *     line discipline will not be closed under us but we may get multiple
+ *     parallel readers and must handle this ourselves. We may also get
+ *     a hangup. Always called in user context, may sleep.
+ *
+ *     This code must be sure never to sleep through a hangup.
+ */
+
+static ssize_t gsmld_read(struct tty_struct *tty, struct file *file,
+                        unsigned char __user *buf, size_t nr)
+{
+       return -EOPNOTSUPP;
+}
+
+/**
+ *     gsmld_write             -       write function for tty
+ *     @tty: tty device
+ *     @file: file object
+ *     @buf: userspace buffer pointer
+ *     @nr: size of I/O
+ *
+ *     Called when the owner of the device wants to send a frame
+ *     itself (or some other control data). The data is transferred
+ *     as-is and must be properly framed and checksummed as appropriate
+ *     by userspace. Frames are either sent whole or not at all as this
+ *     avoids pain user side.
+ */
+
+static ssize_t gsmld_write(struct tty_struct *tty, struct file *file,
+                          const unsigned char *buf, size_t nr)
+{
+       int space = tty_write_room(tty);
+       if (space >= nr)
+               return tty->ops->write(tty, buf, nr);
+       set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+       return -ENOBUFS;
+}
+
+/**
+ *     gsmld_poll              -       poll method for N_GSM0710
+ *     @tty: terminal device
+ *     @file: file accessing it
+ *     @wait: poll table
+ *
+ *     Called when the line discipline is asked to poll() for data or
+ *     for special events. This code is not serialized with respect to
+ *     other events save open/close.
+ *
+ *     This code must be sure never to sleep through a hangup.
+ *     Called without the kernel lock held - fine
+ */
+
+static unsigned int gsmld_poll(struct tty_struct *tty, struct file *file,
+                                                       poll_table *wait)
+{
+       unsigned int mask = 0;
+       struct gsm_mux *gsm = tty->disc_data;
+
+       poll_wait(file, &tty->read_wait, wait);
+       poll_wait(file, &tty->write_wait, wait);
+       if (tty_hung_up_p(file))
+               mask |= POLLHUP;
+       if (!tty_is_writelocked(tty) && tty_write_room(tty) > 0)
+               mask |= POLLOUT | POLLWRNORM;
+       if (gsm->dead)
+               mask |= POLLHUP;
+       return mask;
+}
+
+static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm,
+                                                       struct gsm_config *c)
+{
+       int need_close = 0;
+       int need_restart = 0;
+
+       /* Stuff we don't support yet - UI or I frame transport, windowing */
+       if ((c->adaption !=1 && c->adaption != 2) || c->k)
+               return -EOPNOTSUPP;
+       /* Check the MRU/MTU range looks sane */
+       if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8)
+               return -EINVAL;
+       if (c->n2 < 3)
+               return -EINVAL;
+       if (c->encapsulation > 1)       /* Basic, advanced, no I */
+               return -EINVAL;
+       if (c->initiator > 1)
+               return -EINVAL;
+       if (c->i == 0 || c->i > 2)      /* UIH and UI only */
+               return -EINVAL;
+       /*
+        *      See what is needed for reconfiguration
+        */
+
+       /* Timing fields */
+       if (c->t1 != 0 && c->t1 != gsm->t1)
+               need_restart = 1;
+       if (c->t2 != 0 && c->t2 != gsm->t2)
+               need_restart = 1;
+       if (c->encapsulation != gsm->encoding)
+               need_restart = 1;
+       if (c->adaption != gsm->adaption)
+               need_restart = 1;
+       /* Requires care */
+       if (c->initiator != gsm->initiator)
+               need_close = 1;
+       if (c->mru != gsm->mru)
+               need_restart = 1;
+       if (c->mtu != gsm->mtu)
+               need_restart = 1;
+
+       /*
+        *      Close down what is needed, restart and initiate the new
+        *      configuration
+        */
+
+       if (need_close || need_restart) {
+               gsm_dlci_begin_close(gsm->dlci[0]);
+               /* This will timeout if the link is down due to N2 expiring */
+               wait_event_interruptible(gsm->event,
+                               gsm->dlci[0]->state == DLCI_CLOSED);
+               if (signal_pending(current))
+                       return -EINTR;
+       }
+       if (need_restart)
+               gsm_cleanup_mux(gsm);
+
+       gsm->initiator = c->initiator;
+       gsm->mru = c->mru;
+       gsm->encoding = c->encapsulation;
+       gsm->adaption = c->adaption;
+
+       if (c->i == 1)
+               gsm->ftype = UIH;
+       else if (c->i == 2)
+               gsm->ftype = UI;
+
+       if (c->t1)
+               gsm->t1 = c->t1;
+       if (c->t2)
+               gsm->t2 = c->t2;
+
+       /* FIXME: We need to separate activation/deactivation from adding
+          and removing from the mux array */
+       if (need_restart)
+               gsm_activate_mux(gsm);
+       if (gsm->initiator && need_close)
+               gsm_dlci_begin_open(gsm->dlci[0]);
+       return 0;
+}
+
+static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       struct gsm_config c;
+       struct gsm_mux *gsm = tty->disc_data;
+
+       switch (cmd) {
+       case GSMIOC_GETCONF:
+               memset(&c, 0, sizeof(c));
+               c.adaption = gsm->adaption;
+               c.encapsulation = gsm->encoding;
+               c.initiator = gsm->initiator;
+               c.t1 = gsm->t1;
+               c.t2 = gsm->t2;
+               c.t3 = 0;       /* Not supported */
+               c.n2 = gsm->n2;
+               if (gsm->ftype == UIH)
+                       c.i = 1;
+               else
+                       c.i = 2;
+               printk("Ftype %d i %d\n", gsm->ftype, c.i);
+               c.mru = gsm->mru;
+               c.mtu = gsm->mtu;
+               c.k = 0;
+               if (copy_to_user((void *)arg, &c, sizeof(c)))
+                       return -EFAULT;
+               return 0;
+       case GSMIOC_SETCONF:
+               if (copy_from_user(&c, (void *)arg, sizeof(c)))
+                       return -EFAULT;
+               return gsmld_config(tty, gsm, &c);
+       default:
+               return n_tty_ioctl_helper(tty, file, cmd, arg);
+       }
+}
+
+
+/* Line discipline for real tty */
+struct tty_ldisc_ops tty_ldisc_packet = {
+       .owner           = THIS_MODULE,
+       .magic           = TTY_LDISC_MAGIC,
+       .name            = "n_gsm",
+       .open            = gsmld_open,
+       .close           = gsmld_close,
+       .flush_buffer    = gsmld_flush_buffer,
+       .chars_in_buffer = gsmld_chars_in_buffer,
+       .read            = gsmld_read,
+       .write           = gsmld_write,
+       .ioctl           = gsmld_ioctl,
+       .poll            = gsmld_poll,
+       .receive_buf     = gsmld_receive_buf,
+       .write_wakeup    = gsmld_write_wakeup
+};
+
+/*
+ *     Virtual tty side
+ */
+
+#define TX_SIZE                512
+
+static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk)
+{
+       u8 modembits[5];
+       struct gsm_control *ctrl;
+       int len = 2;
+
+       if (brk)
+               len++;
+
+       modembits[0] = len << 1 | EA;           /* Data bytes */
+       modembits[1] = dlci->addr << 2 | 3;     /* DLCI, EA, 1 */
+       modembits[2] = gsm_encode_modem(dlci) << 1 | EA;
+       if (brk)
+               modembits[3] = brk << 4 | 2 | EA;       /* Valid, EA */
+       ctrl = gsm_control_send(dlci->gsm, CMD_MSC, modembits, len + 1);
+       if (ctrl == NULL)
+               return -ENOMEM;
+       return gsm_control_wait(dlci->gsm, ctrl);
+}
+
+static int gsm_carrier_raised(struct tty_port *port)
+{
+       struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
+       /* Not yet open so no carrier info */
+       if (dlci->state != DLCI_OPEN)
+               return 0;
+       if (debug & 2)
+               return 1;
+       return dlci->modem_rx & TIOCM_CD;
+}
+
+static void gsm_dtr_rts(struct tty_port *port, int onoff)
+{
+       struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
+       unsigned int modem_tx = dlci->modem_tx;
+       if (onoff)
+               modem_tx |= TIOCM_DTR | TIOCM_RTS;
+       else
+               modem_tx &= ~(TIOCM_DTR | TIOCM_RTS);
+       if (modem_tx != dlci->modem_tx) {
+               dlci->modem_tx = modem_tx;
+               gsmtty_modem_update(dlci, 0);
+       }
+}
+
+static const struct tty_port_operations gsm_port_ops = {
+       .carrier_raised = gsm_carrier_raised,
+       .dtr_rts = gsm_dtr_rts,
+};
+
+
+static int gsmtty_open(struct tty_struct *tty, struct file *filp)
+{
+       struct gsm_mux *gsm;
+       struct gsm_dlci *dlci;
+       struct tty_port *port;
+       unsigned int line = tty->index;
+       unsigned int mux = line >> 6;
+
+       line = line & 0x3F;
+
+       if (mux >= MAX_MUX)
+               return -ENXIO;
+       /* FIXME: we need to lock gsm_mux for lifetimes of ttys eventually */
+       if (gsm_mux[mux] == NULL)
+               return -EUNATCH;
+       if (line == 0 || line > 61)     /* 62/63 reserved */
+               return -ECHRNG;
+       gsm = gsm_mux[mux];
+       if (gsm->dead)
+               return -EL2HLT;
+       dlci = gsm->dlci[line];
+       if (dlci == NULL)
+               dlci = gsm_dlci_alloc(gsm, line);
+       if (dlci == NULL)
+               return -ENOMEM;
+       port = &dlci->port;
+       port->count++;
+       tty->driver_data = dlci;
+       tty_port_tty_set(port, tty);
+
+       dlci->modem_rx = 0;
+       /* We could in theory open and close before we wait - eg if we get
+          a DM straight back. This is ok as that will have caused a hangup */
+       set_bit(ASYNCB_INITIALIZED, &port->flags);
+       /* Start sending off SABM messages */
+       gsm_dlci_begin_open(dlci);
+       /* And wait for virtual carrier */
+       return tty_port_block_til_ready(port, tty, filp);
+}
+
+static void gsmtty_close(struct tty_struct *tty, struct file *filp)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       if (dlci == NULL)
+               return;
+       if (tty_port_close_start(&dlci->port, tty, filp) == 0)
+               return;
+       gsm_dlci_begin_close(dlci);
+       tty_port_close_end(&dlci->port, tty);
+       tty_port_tty_set(&dlci->port, NULL);
+}
+
+static void gsmtty_hangup(struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       tty_port_hangup(&dlci->port);
+       gsm_dlci_begin_close(dlci);
+}
+
+static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf,
+                                                                   int len)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       /* Stuff the bytes into the fifo queue */
+       int sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock);
+       /* Need to kick the channel */
+       gsm_dlci_data_kick(dlci);
+       return sent;
+}
+
+static int gsmtty_write_room(struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       return TX_SIZE - kfifo_len(dlci->fifo);
+}
+
+static int gsmtty_chars_in_buffer(struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       return kfifo_len(dlci->fifo);
+}
+
+static void gsmtty_flush_buffer(struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       /* Caution needed: If we implement reliable transport classes
+          then the data being transmitted can't simply be junked once
+          it has first hit the stack. Until then we can just blow it
+          away */
+       kfifo_reset(dlci->fifo);
+       /* Need to unhook this DLCI from the transmit queue logic */
+}
+
+static void gsmtty_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+       /* The FIFO handles the queue so the kernel will do the right
+          thing waiting on chars_in_buffer before calling us. No work
+          to do here */
+}
+
+static int gsmtty_tiocmget(struct tty_struct *tty, struct file *filp)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       return dlci->modem_rx;
+}
+
+static int gsmtty_tiocmset(struct tty_struct *tty, struct file *filp,
+       unsigned int set, unsigned int clear)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       unsigned int modem_tx = dlci->modem_tx;
+
+       modem_tx &= clear;
+       modem_tx |= set;
+
+       if (modem_tx != dlci->modem_tx) {
+               dlci->modem_tx = modem_tx;
+               return gsmtty_modem_update(dlci, 0);
+       }
+       return 0;
+}
+
+
+static int gsmtty_ioctl(struct tty_struct *tty, struct file *filp,
+                       unsigned int cmd, unsigned long arg)
+{
+       return -ENOIOCTLCMD;
+}
+
+static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
+{
+       /* For the moment its fixed. In actual fact the speed information
+          for the virtual channel can be propogated in both directions by
+          the RPN control message. This however rapidly gets nasty as we
+          then have to remap modem signals each way according to whether
+          our virtual cable is null modem etc .. */
+       tty_termios_copy_hw(tty->termios, old);
+}
+
+static void gsmtty_throttle(struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       if (tty->termios->c_cflag & CRTSCTS)
+               dlci->modem_tx &= ~TIOCM_DTR;
+       dlci->throttled = 1;
+       /* Send an MSC with DTR cleared */
+       gsmtty_modem_update(dlci, 0);
+}
+
+static void gsmtty_unthrottle(struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       if (tty->termios->c_cflag & CRTSCTS)
+               dlci->modem_tx |= TIOCM_DTR;
+       dlci->throttled = 0;
+       /* Send an MSC with DTR set */
+       gsmtty_modem_update(dlci, 0);
+}
+
+static int gsmtty_break_ctl(struct tty_struct *tty, int state)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       int encode = 0; /* Off */
+
+       if (state == -1)        /* "On indefinitely" - we can't encode this
+                                   properly */
+               encode = 0x0F;
+       else if (state > 0) {
+               encode = state / 200;   /* mS to encoding */
+               if (encode > 0x0F)
+                       encode = 0x0F;  /* Best effort */
+       }
+       return gsmtty_modem_update(dlci, encode);
+}
+
+static struct tty_driver *gsm_tty_driver;
+
+/* Virtual ttys for the demux */
+static const struct tty_operations gsmtty_ops = {
+       .open                   = gsmtty_open,
+       .close                  = gsmtty_close,
+       .write                  = gsmtty_write,
+       .write_room             = gsmtty_write_room,
+       .chars_in_buffer        = gsmtty_chars_in_buffer,
+       .flush_buffer           = gsmtty_flush_buffer,
+       .ioctl                  = gsmtty_ioctl,
+       .throttle               = gsmtty_throttle,
+       .unthrottle             = gsmtty_unthrottle,
+       .set_termios            = gsmtty_set_termios,
+       .hangup                 = gsmtty_hangup,
+       .wait_until_sent        = gsmtty_wait_until_sent,
+       .tiocmget               = gsmtty_tiocmget,
+       .tiocmset               = gsmtty_tiocmset,
+       .break_ctl              = gsmtty_break_ctl,
+};
+
+
+
+static int __init gsm_init(void)
+{
+       /* Fill in our line protocol discipline, and register it */
+       int status = tty_register_ldisc(N_GSM0710, &tty_ldisc_packet);
+       if (status != 0) {
+               printk(KERN_ERR "n_gsm: can't register line discipline (err = %d)\n", status);
+               return status;
+       }
+
+       gsm_tty_driver = alloc_tty_driver(256);
+       if (!gsm_tty_driver) {
+               tty_unregister_ldisc(N_GSM0710);
+               printk(KERN_ERR "gsm_init: tty allocation failed.\n");
+               return -EINVAL;
+       }
+       gsm_tty_driver->owner   = THIS_MODULE;
+       gsm_tty_driver->driver_name     = "gsmtty";
+       gsm_tty_driver->name            = "gsmtty";
+       gsm_tty_driver->major           = 0;    /* Dynamic */
+       gsm_tty_driver->minor_start     = 0;
+       gsm_tty_driver->type            = TTY_DRIVER_TYPE_SERIAL;
+       gsm_tty_driver->subtype = SERIAL_TYPE_NORMAL;
+       gsm_tty_driver->flags   = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV
+                                                       | TTY_DRIVER_HARDWARE_BREAK;
+       gsm_tty_driver->init_termios    = tty_std_termios;
+       /* Fixme */
+       gsm_tty_driver->init_termios.c_lflag &= ~ECHO;
+       tty_set_operations(gsm_tty_driver, &gsmtty_ops);
+
+       spin_lock_init(&gsm_mux_lock);
+
+       if (tty_register_driver(gsm_tty_driver)) {
+               put_tty_driver(gsm_tty_driver);
+               tty_unregister_ldisc(N_GSM0710);
+               printk(KERN_ERR "gsm_init: tty registration failed.\n");
+               return -EBUSY;
+       }
+       printk(KERN_INFO "gsm_init: loaded as %d,%d.\n", gsm_tty_driver->major, gsm_tty_driver->minor_start);
+       return 0;
+}
+
+static void __exit gsm_exit(void)
+{
+       int status = tty_unregister_ldisc(N_GSM0710);
+       if (status != 0)
+               printk(KERN_ERR "n_gsm: can't unregister line discipline (err = %d)\n", status);
+       tty_unregister_driver(gsm_tty_driver);
+       put_tty_driver(gsm_tty_driver);
+       printk(KERN_INFO "gsm_init: unloaded.\n");
+}
+
+module_init(gsm_init);
+module_exit(gsm_exit);
+
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_LDISC(N_GSM0710);
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
new file mode 100644 (file)
index 0000000..47d3228
--- /dev/null
@@ -0,0 +1,1007 @@
+/* generic HDLC line discipline for Linux
+ *
+ * Written by Paul Fulghum paulkf@microgate.com
+ * for Microgate Corporation
+ *
+ * Microgate and SyncLink are registered trademarks of Microgate Corporation
+ *
+ * Adapted from ppp.c, written by Michael Callahan <callahan@maths.ox.ac.uk>,
+ *     Al Longyear <longyear@netcom.com>,
+ *     Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
+ *
+ * Original release 01/11/99
+ *
+ * This code is released under the GNU General Public License (GPL)
+ *
+ * This module implements the tty line discipline N_HDLC for use with
+ * tty device drivers that support bit-synchronous HDLC communications.
+ *
+ * All HDLC data is frame oriented which means:
+ *
+ * 1. tty write calls represent one complete transmit frame of data
+ *    The device driver should accept the complete frame or none of 
+ *    the frame (busy) in the write method. Each write call should have
+ *    a byte count in the range of 2-65535 bytes (2 is min HDLC frame
+ *    with 1 addr byte and 1 ctrl byte). The max byte count of 65535
+ *    should include any crc bytes required. For example, when using
+ *    CCITT CRC32, 4 crc bytes are required, so the maximum size frame
+ *    the application may transmit is limited to 65531 bytes. For CCITT
+ *    CRC16, the maximum application frame size would be 65533.
+ *
+ *
+ * 2. receive callbacks from the device driver represents
+ *    one received frame. The device driver should bypass
+ *    the tty flip buffer and call the line discipline receive
+ *    callback directly to avoid fragmenting or concatenating
+ *    multiple frames into a single receive callback.
+ *
+ *    The HDLC line discipline queues the receive frames in separate
+ *    buffers so complete receive frames can be returned by the
+ *    tty read calls.
+ *
+ * 3. tty read calls returns an entire frame of data or nothing.
+ *    
+ * 4. all send and receive data is considered raw. No processing
+ *    or translation is performed by the line discipline, regardless
+ *    of the tty flags
+ *
+ * 5. When line discipline is queried for the amount of receive
+ *    data available (FIOC), 0 is returned if no data available,
+ *    otherwise the count of the next available frame is returned.
+ *    (instead of the sum of all received frame counts).
+ *
+ * These conventions allow the standard tty programming interface
+ * to be used for synchronous HDLC applications when used with
+ * this line discipline (or another line discipline that is frame
+ * oriented such as N_PPP).
+ *
+ * The SyncLink driver (synclink.c) implements both asynchronous
+ * (using standard line discipline N_TTY) and synchronous HDLC
+ * (using N_HDLC) communications, with the latter using the above
+ * conventions.
+ *
+ * This implementation is very basic and does not maintain
+ * any statistics. The main point is to enforce the raw data
+ * and frame orientation of HDLC communications.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define HDLC_MAGIC 0x239e
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+
+#undef VERSION
+#define VERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
+
+#include <linux/poll.h>
+#include <linux/in.h>
+#include <linux/ioctl.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/smp_lock.h>
+#include <linux/string.h>      /* used in new tty drivers */
+#include <linux/signal.h>      /* used in new tty drivers */
+#include <linux/if.h>
+#include <linux/bitops.h>
+
+#include <asm/system.h>
+#include <asm/termios.h>
+#include <asm/uaccess.h>
+
+/*
+ * Buffers for individual HDLC frames
+ */
+#define MAX_HDLC_FRAME_SIZE 65535 
+#define DEFAULT_RX_BUF_COUNT 10
+#define MAX_RX_BUF_COUNT 60
+#define DEFAULT_TX_BUF_COUNT 3
+
+struct n_hdlc_buf {
+       struct n_hdlc_buf *link;
+       int               count;
+       char              buf[1];
+};
+
+#define        N_HDLC_BUF_SIZE (sizeof(struct n_hdlc_buf) + maxframe)
+
+struct n_hdlc_buf_list {
+       struct n_hdlc_buf *head;
+       struct n_hdlc_buf *tail;
+       int               count;
+       spinlock_t        spinlock;
+};
+
+/**
+ * struct n_hdlc - per device instance data structure
+ * @magic - magic value for structure
+ * @flags - miscellaneous control flags
+ * @tty - ptr to TTY structure
+ * @backup_tty - TTY to use if tty gets closed
+ * @tbusy - reentrancy flag for tx wakeup code
+ * @woke_up - FIXME: describe this field
+ * @tbuf - currently transmitting tx buffer
+ * @tx_buf_list - list of pending transmit frame buffers
+ * @rx_buf_list - list of received frame buffers
+ * @tx_free_buf_list - list unused transmit frame buffers
+ * @rx_free_buf_list - list unused received frame buffers
+ */
+struct n_hdlc {
+       int                     magic;
+       __u32                   flags;
+       struct tty_struct       *tty;
+       struct tty_struct       *backup_tty;
+       int                     tbusy;
+       int                     woke_up;
+       struct n_hdlc_buf       *tbuf;
+       struct n_hdlc_buf_list  tx_buf_list;
+       struct n_hdlc_buf_list  rx_buf_list;
+       struct n_hdlc_buf_list  tx_free_buf_list;
+       struct n_hdlc_buf_list  rx_free_buf_list;
+};
+
+/*
+ * HDLC buffer list manipulation functions
+ */
+static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list);
+static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
+                          struct n_hdlc_buf *buf);
+static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
+
+/* Local functions */
+
+static struct n_hdlc *n_hdlc_alloc (void);
+
+/* debug level can be set by insmod for debugging purposes */
+#define DEBUG_LEVEL_INFO       1
+static int debuglevel;
+
+/* max frame size for memory allocations */
+static int maxframe = 4096;
+
+/* TTY callbacks */
+
+static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
+                          __u8 __user *buf, size_t nr);
+static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
+                           const unsigned char *buf, size_t nr);
+static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
+                           unsigned int cmd, unsigned long arg);
+static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
+                                   poll_table *wait);
+static int n_hdlc_tty_open(struct tty_struct *tty);
+static void n_hdlc_tty_close(struct tty_struct *tty);
+static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp,
+                              char *fp, int count);
+static void n_hdlc_tty_wakeup(struct tty_struct *tty);
+
+#define bset(p,b)      ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
+
+#define tty2n_hdlc(tty)        ((struct n_hdlc *) ((tty)->disc_data))
+#define n_hdlc2tty(n_hdlc)     ((n_hdlc)->tty)
+
+static void flush_rx_queue(struct tty_struct *tty)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+       struct n_hdlc_buf *buf;
+
+       while ((buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list)))
+               n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, buf);
+}
+
+static void flush_tx_queue(struct tty_struct *tty)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+       struct n_hdlc_buf *buf;
+       unsigned long flags;
+
+       while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list)))
+               n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf);
+       spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
+       if (n_hdlc->tbuf) {
+               n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, n_hdlc->tbuf);
+               n_hdlc->tbuf = NULL;
+       }
+       spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
+}
+
+static struct tty_ldisc_ops n_hdlc_ldisc = {
+       .owner          = THIS_MODULE,
+       .magic          = TTY_LDISC_MAGIC,
+       .name           = "hdlc",
+       .open           = n_hdlc_tty_open,
+       .close          = n_hdlc_tty_close,
+       .read           = n_hdlc_tty_read,
+       .write          = n_hdlc_tty_write,
+       .ioctl          = n_hdlc_tty_ioctl,
+       .poll           = n_hdlc_tty_poll,
+       .receive_buf    = n_hdlc_tty_receive,
+       .write_wakeup   = n_hdlc_tty_wakeup,
+       .flush_buffer   = flush_rx_queue,
+};
+
+/**
+ * n_hdlc_release - release an n_hdlc per device line discipline info structure
+ * @n_hdlc - per device line discipline info structure
+ */
+static void n_hdlc_release(struct n_hdlc *n_hdlc)
+{
+       struct tty_struct *tty = n_hdlc2tty (n_hdlc);
+       struct n_hdlc_buf *buf;
+       
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_release() called\n",__FILE__,__LINE__);
+               
+       /* Ensure that the n_hdlcd process is not hanging on select()/poll() */
+       wake_up_interruptible (&tty->read_wait);
+       wake_up_interruptible (&tty->write_wait);
+
+       if (tty->disc_data == n_hdlc)
+               tty->disc_data = NULL;  /* Break the tty->n_hdlc link */
+
+       /* Release transmit and receive buffers */
+       for(;;) {
+               buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
+               if (buf) {
+                       kfree(buf);
+               } else
+                       break;
+       }
+       for(;;) {
+               buf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);
+               if (buf) {
+                       kfree(buf);
+               } else
+                       break;
+       }
+       for(;;) {
+               buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
+               if (buf) {
+                       kfree(buf);
+               } else
+                       break;
+       }
+       for(;;) {
+               buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
+               if (buf) {
+                       kfree(buf);
+               } else
+                       break;
+       }
+       kfree(n_hdlc->tbuf);
+       kfree(n_hdlc);
+       
+}      /* end of n_hdlc_release() */
+
+/**
+ * n_hdlc_tty_close - line discipline close
+ * @tty - pointer to tty info structure
+ *
+ * Called when the line discipline is changed to something
+ * else, the tty is closed, or the tty detects a hangup.
+ */
+static void n_hdlc_tty_close(struct tty_struct *tty)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_close() called\n",__FILE__,__LINE__);
+               
+       if (n_hdlc != NULL) {
+               if (n_hdlc->magic != HDLC_MAGIC) {
+                       printk (KERN_WARNING"n_hdlc: trying to close unopened tty!\n");
+                       return;
+               }
+#if defined(TTY_NO_WRITE_SPLIT)
+               clear_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
+#endif
+               tty->disc_data = NULL;
+               if (tty == n_hdlc->backup_tty)
+                       n_hdlc->backup_tty = NULL;
+               if (tty != n_hdlc->tty)
+                       return;
+               if (n_hdlc->backup_tty) {
+                       n_hdlc->tty = n_hdlc->backup_tty;
+               } else {
+                       n_hdlc_release (n_hdlc);
+               }
+       }
+       
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_close() success\n",__FILE__,__LINE__);
+               
+}      /* end of n_hdlc_tty_close() */
+
+/**
+ * n_hdlc_tty_open - called when line discipline changed to n_hdlc
+ * @tty - pointer to tty info structure
+ *
+ * Returns 0 if success, otherwise error code
+ */
+static int n_hdlc_tty_open (struct tty_struct *tty)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_open() called (device=%s)\n",
+               __FILE__,__LINE__,
+               tty->name);
+               
+       /* There should not be an existing table for this slot. */
+       if (n_hdlc) {
+               printk (KERN_ERR"n_hdlc_tty_open:tty already associated!\n" );
+               return -EEXIST;
+       }
+       
+       n_hdlc = n_hdlc_alloc();
+       if (!n_hdlc) {
+               printk (KERN_ERR "n_hdlc_alloc failed\n");
+               return -ENFILE;
+       }
+               
+       tty->disc_data = n_hdlc;
+       n_hdlc->tty    = tty;
+       tty->receive_room = 65536;
+       
+#if defined(TTY_NO_WRITE_SPLIT)
+       /* change tty_io write() to not split large writes into 8K chunks */
+       set_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
+#endif
+       
+       /* flush receive data from driver */
+       tty_driver_flush_buffer(tty);
+               
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_open() success\n",__FILE__,__LINE__);
+               
+       return 0;
+       
+}      /* end of n_tty_hdlc_open() */
+
+/**
+ * n_hdlc_send_frames - send frames on pending send buffer list
+ * @n_hdlc - pointer to ldisc instance data
+ * @tty - pointer to tty instance data
+ *
+ * Send frames on pending send buffer list until the driver does not accept a
+ * frame (busy) this function is called after adding a frame to the send buffer
+ * list and by the tty wakeup callback.
+ */
+static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
+{
+       register int actual;
+       unsigned long flags;
+       struct n_hdlc_buf *tbuf;
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__);
+ check_again:
+               
+       spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
+       if (n_hdlc->tbusy) {
+               n_hdlc->woke_up = 1;
+               spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
+               return;
+       }
+       n_hdlc->tbusy = 1;
+       n_hdlc->woke_up = 0;
+       spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
+
+       /* get current transmit buffer or get new transmit */
+       /* buffer from list of pending transmit buffers */
+               
+       tbuf = n_hdlc->tbuf;
+       if (!tbuf)
+               tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
+               
+       while (tbuf) {
+               if (debuglevel >= DEBUG_LEVEL_INFO)     
+                       printk("%s(%d)sending frame %p, count=%d\n",
+                               __FILE__,__LINE__,tbuf,tbuf->count);
+                       
+               /* Send the next block of data to device */
+               tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+               actual = tty->ops->write(tty, tbuf->buf, tbuf->count);
+
+               /* rollback was possible and has been done */
+               if (actual == -ERESTARTSYS) {
+                       n_hdlc->tbuf = tbuf;
+                       break;
+               }
+               /* if transmit error, throw frame away by */
+               /* pretending it was accepted by driver */
+               if (actual < 0)
+                       actual = tbuf->count;
+               
+               if (actual == tbuf->count) {
+                       if (debuglevel >= DEBUG_LEVEL_INFO)     
+                               printk("%s(%d)frame %p completed\n",
+                                       __FILE__,__LINE__,tbuf);
+                                       
+                       /* free current transmit buffer */
+                       n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf);
+                       
+                       /* this tx buffer is done */
+                       n_hdlc->tbuf = NULL;
+                       
+                       /* wait up sleeping writers */
+                       wake_up_interruptible(&tty->write_wait);
+       
+                       /* get next pending transmit buffer */
+                       tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
+               } else {
+                       if (debuglevel >= DEBUG_LEVEL_INFO)     
+                               printk("%s(%d)frame %p pending\n",
+                                       __FILE__,__LINE__,tbuf);
+                                       
+                       /* buffer not accepted by driver */
+                       /* set this buffer as pending buffer */
+                       n_hdlc->tbuf = tbuf;
+                       break;
+               }
+       }
+       
+       if (!tbuf)
+               tty->flags  &= ~(1 << TTY_DO_WRITE_WAKEUP);
+       
+       /* Clear the re-entry flag */
+       spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
+       n_hdlc->tbusy = 0;
+       spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); 
+       
+        if (n_hdlc->woke_up)
+         goto check_again;
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_send_frames() exit\n",__FILE__,__LINE__);
+               
+}      /* end of n_hdlc_send_frames() */
+
+/**
+ * n_hdlc_tty_wakeup - Callback for transmit wakeup
+ * @tty        - pointer to associated tty instance data
+ *
+ * Called when low level device driver can accept more send data.
+ */
+static void n_hdlc_tty_wakeup(struct tty_struct *tty)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_wakeup() called\n",__FILE__,__LINE__);
+               
+       if (!n_hdlc)
+               return;
+
+       if (tty != n_hdlc->tty) {
+               tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+               return;
+       }
+
+       n_hdlc_send_frames (n_hdlc, tty);
+               
+}      /* end of n_hdlc_tty_wakeup() */
+
+/**
+ * n_hdlc_tty_receive - Called by tty driver when receive data is available
+ * @tty        - pointer to tty instance data
+ * @data - pointer to received data
+ * @flags - pointer to flags for data
+ * @count - count of received data in bytes
+ *
+ * Called by tty low level driver when receive data is available. Data is
+ * interpreted as one HDLC frame.
+ */
+static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
+                              char *flags, int count)
+{
+       register struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+       register struct n_hdlc_buf *buf;
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_receive() called count=%d\n",
+                       __FILE__,__LINE__, count);
+               
+       /* This can happen if stuff comes in on the backup tty */
+       if (!n_hdlc || tty != n_hdlc->tty)
+               return;
+               
+       /* verify line is using HDLC discipline */
+       if (n_hdlc->magic != HDLC_MAGIC) {
+               printk("%s(%d) line not using HDLC discipline\n",
+                       __FILE__,__LINE__);
+               return;
+       }
+       
+       if ( count>maxframe ) {
+               if (debuglevel >= DEBUG_LEVEL_INFO)     
+                       printk("%s(%d) rx count>maxframesize, data discarded\n",
+                              __FILE__,__LINE__);
+               return;
+       }
+
+       /* get a free HDLC buffer */    
+       buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
+       if (!buf) {
+               /* no buffers in free list, attempt to allocate another rx buffer */
+               /* unless the maximum count has been reached */
+               if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT)
+                       buf = kmalloc(N_HDLC_BUF_SIZE, GFP_ATOMIC);
+       }
+       
+       if (!buf) {
+               if (debuglevel >= DEBUG_LEVEL_INFO)     
+                       printk("%s(%d) no more rx buffers, data discarded\n",
+                              __FILE__,__LINE__);
+               return;
+       }
+               
+       /* copy received data to HDLC buffer */
+       memcpy(buf->buf,data,count);
+       buf->count=count;
+
+       /* add HDLC buffer to list of received frames */
+       n_hdlc_buf_put(&n_hdlc->rx_buf_list, buf);
+       
+       /* wake up any blocked reads and perform async signalling */
+       wake_up_interruptible (&tty->read_wait);
+       if (n_hdlc->tty->fasync != NULL)
+               kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN);
+
+}      /* end of n_hdlc_tty_receive() */
+
+/**
+ * n_hdlc_tty_read - Called to retrieve one frame of data (if available)
+ * @tty - pointer to tty instance data
+ * @file - pointer to open file object
+ * @buf - pointer to returned data buffer
+ * @nr - size of returned data buffer
+ *     
+ * Returns the number of bytes returned or error code.
+ */
+static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
+                          __u8 __user *buf, size_t nr)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+       int ret;
+       struct n_hdlc_buf *rbuf;
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__);
+               
+       /* Validate the pointers */
+       if (!n_hdlc)
+               return -EIO;
+
+       /* verify user access to buffer */
+       if (!access_ok(VERIFY_WRITE, buf, nr)) {
+               printk(KERN_WARNING "%s(%d) n_hdlc_tty_read() can't verify user "
+               "buffer\n", __FILE__, __LINE__);
+               return -EFAULT;
+       }
+
+       tty_lock();
+
+       for (;;) {
+               if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
+                       tty_unlock();
+                       return -EIO;
+               }
+
+               n_hdlc = tty2n_hdlc (tty);
+               if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC ||
+                        tty != n_hdlc->tty) {
+                       tty_unlock();
+                       return 0;
+               }
+
+               rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
+               if (rbuf)
+                       break;
+                       
+               /* no data */
+               if (file->f_flags & O_NONBLOCK) {
+                       tty_unlock();
+                       return -EAGAIN;
+               }
+                       
+               interruptible_sleep_on (&tty->read_wait);
+               if (signal_pending(current)) {
+                       tty_unlock();
+                       return -EINTR;
+               }
+       }
+               
+       if (rbuf->count > nr)
+               /* frame too large for caller's buffer (discard frame) */
+               ret = -EOVERFLOW;
+       else {
+               /* Copy the data to the caller's buffer */
+               if (copy_to_user(buf, rbuf->buf, rbuf->count))
+                       ret = -EFAULT;
+               else
+                       ret = rbuf->count;
+       }
+       
+       /* return HDLC buffer to free list unless the free list */
+       /* count has exceeded the default value, in which case the */
+       /* buffer is freed back to the OS to conserve memory */
+       if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT)
+               kfree(rbuf);
+       else    
+               n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf);
+       tty_unlock();
+       return ret;
+       
+}      /* end of n_hdlc_tty_read() */
+
+/**
+ * n_hdlc_tty_write - write a single frame of data to device
+ * @tty        - pointer to associated tty device instance data
+ * @file - pointer to file object data
+ * @data - pointer to transmit data (one frame)
+ * @count - size of transmit frame in bytes
+ *             
+ * Returns the number of bytes written (or error code).
+ */
+static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
+                           const unsigned char *data, size_t count)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+       int error = 0;
+       DECLARE_WAITQUEUE(wait, current);
+       struct n_hdlc_buf *tbuf;
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_write() called count=%Zd\n",
+                       __FILE__,__LINE__,count);
+               
+       /* Verify pointers */
+       if (!n_hdlc)
+               return -EIO;
+
+       if (n_hdlc->magic != HDLC_MAGIC)
+               return -EIO;
+
+       /* verify frame size */
+       if (count > maxframe ) {
+               if (debuglevel & DEBUG_LEVEL_INFO)
+                       printk (KERN_WARNING
+                               "n_hdlc_tty_write: truncating user packet "
+                               "from %lu to %d\n", (unsigned long) count,
+                               maxframe );
+               count = maxframe;
+       }
+       
+       tty_lock();
+
+       add_wait_queue(&tty->write_wait, &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+       
+       /* Allocate transmit buffer */
+       /* sleep until transmit buffer available */             
+       while (!(tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list))) {
+               if (file->f_flags & O_NONBLOCK) {
+                       error = -EAGAIN;
+                       break;
+               }
+               schedule();
+                       
+               n_hdlc = tty2n_hdlc (tty);
+               if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || 
+                   tty != n_hdlc->tty) {
+                       printk("n_hdlc_tty_write: %p invalid after wait!\n", n_hdlc);
+                       error = -EIO;
+                       break;
+               }
+                       
+               if (signal_pending(current)) {
+                       error = -EINTR;
+                       break;
+               }
+       }
+
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&tty->write_wait, &wait);
+
+       if (!error) {           
+               /* Retrieve the user's buffer */
+               memcpy(tbuf->buf, data, count);
+
+               /* Send the data */
+               tbuf->count = error = count;
+               n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf);
+               n_hdlc_send_frames(n_hdlc,tty);
+       }
+       tty_unlock();
+       return error;
+       
+}      /* end of n_hdlc_tty_write() */
+
+/**
+ * n_hdlc_tty_ioctl - process IOCTL system call for the tty device.
+ * @tty - pointer to tty instance data
+ * @file - pointer to open file object for device
+ * @cmd - IOCTL command code
+ * @arg - argument for IOCTL call (cmd dependent)
+ *
+ * Returns command dependent result.
+ */
+static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
+                           unsigned int cmd, unsigned long arg)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+       int error = 0;
+       int count;
+       unsigned long flags;
+       
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_ioctl() called %d\n",
+                       __FILE__,__LINE__,cmd);
+               
+       /* Verify the status of the device */
+       if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC)
+               return -EBADF;
+
+       switch (cmd) {
+       case FIONREAD:
+               /* report count of read data available */
+               /* in next available frame (if any) */
+               spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
+               if (n_hdlc->rx_buf_list.head)
+                       count = n_hdlc->rx_buf_list.head->count;
+               else
+                       count = 0;
+               spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
+               error = put_user(count, (int __user *)arg);
+               break;
+
+       case TIOCOUTQ:
+               /* get the pending tx byte count in the driver */
+               count = tty_chars_in_buffer(tty);
+               /* add size of next output frame in queue */
+               spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
+               if (n_hdlc->tx_buf_list.head)
+                       count += n_hdlc->tx_buf_list.head->count;
+               spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags);
+               error = put_user(count, (int __user *)arg);
+               break;
+
+       case TCFLSH:
+               switch (arg) {
+               case TCIOFLUSH:
+               case TCOFLUSH:
+                       flush_tx_queue(tty);
+               }
+               /* fall through to default */
+
+       default:
+               error = n_tty_ioctl_helper(tty, file, cmd, arg);
+               break;
+       }
+       return error;
+       
+}      /* end of n_hdlc_tty_ioctl() */
+
+/**
+ * n_hdlc_tty_poll - TTY callback for poll system call
+ * @tty - pointer to tty instance data
+ * @filp - pointer to open file object for device
+ * @poll_table - wait queue for operations
+ * 
+ * Determine which operations (read/write) will not block and return info
+ * to caller.
+ * Returns a bit mask containing info on which ops will not block.
+ */
+static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
+                                   poll_table *wait)
+{
+       struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
+       unsigned int mask = 0;
+
+       if (debuglevel >= DEBUG_LEVEL_INFO)     
+               printk("%s(%d)n_hdlc_tty_poll() called\n",__FILE__,__LINE__);
+               
+       if (n_hdlc && n_hdlc->magic == HDLC_MAGIC && tty == n_hdlc->tty) {
+               /* queue current process into any wait queue that */
+               /* may awaken in the future (read and write) */
+
+               poll_wait(filp, &tty->read_wait, wait);
+               poll_wait(filp, &tty->write_wait, wait);
+
+               /* set bits for operations that won't block */
+               if (n_hdlc->rx_buf_list.head)
+                       mask |= POLLIN | POLLRDNORM;    /* readable */
+               if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+                       mask |= POLLHUP;
+               if (tty_hung_up_p(filp))
+                       mask |= POLLHUP;
+               if (!tty_is_writelocked(tty) &&
+                               n_hdlc->tx_free_buf_list.head)
+                       mask |= POLLOUT | POLLWRNORM;   /* writable */
+       }
+       return mask;
+}      /* end of n_hdlc_tty_poll() */
+
+/**
+ * n_hdlc_alloc - allocate an n_hdlc instance data structure
+ *
+ * Returns a pointer to newly created structure if success, otherwise %NULL
+ */
+static struct n_hdlc *n_hdlc_alloc(void)
+{
+       struct n_hdlc_buf *buf;
+       int i;
+       struct n_hdlc *n_hdlc = kmalloc(sizeof(*n_hdlc), GFP_KERNEL);
+
+       if (!n_hdlc)
+               return NULL;
+
+       memset(n_hdlc, 0, sizeof(*n_hdlc));
+
+       n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list);
+       n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list);
+       n_hdlc_buf_list_init(&n_hdlc->rx_buf_list);
+       n_hdlc_buf_list_init(&n_hdlc->tx_buf_list);
+       
+       /* allocate free rx buffer list */
+       for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
+               buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL);
+               if (buf)
+                       n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,buf);
+               else if (debuglevel >= DEBUG_LEVEL_INFO)        
+                       printk("%s(%d)n_hdlc_alloc(), kalloc() failed for rx buffer %d\n",__FILE__,__LINE__, i);
+       }
+       
+       /* allocate free tx buffer list */
+       for(i=0;i<DEFAULT_TX_BUF_COUNT;i++) {
+               buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL);
+               if (buf)
+                       n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,buf);
+               else if (debuglevel >= DEBUG_LEVEL_INFO)        
+                       printk("%s(%d)n_hdlc_alloc(), kalloc() failed for tx buffer %d\n",__FILE__,__LINE__, i);
+       }
+       
+       /* Initialize the control block */
+       n_hdlc->magic  = HDLC_MAGIC;
+       n_hdlc->flags  = 0;
+       
+       return n_hdlc;
+       
+}      /* end of n_hdlc_alloc() */
+
+/**
+ * n_hdlc_buf_list_init - initialize specified HDLC buffer list
+ * @list - pointer to buffer list
+ */
+static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list)
+{
+       memset(list, 0, sizeof(*list));
+       spin_lock_init(&list->spinlock);
+}      /* end of n_hdlc_buf_list_init() */
+
+/**
+ * n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
+ * @list - pointer to buffer list
+ * @buf        - pointer to buffer
+ */
+static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
+                          struct n_hdlc_buf *buf)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&list->spinlock,flags);
+       
+       buf->link=NULL;
+       if (list->tail)
+               list->tail->link = buf;
+       else
+               list->head = buf;
+       list->tail = buf;
+       (list->count)++;
+       
+       spin_unlock_irqrestore(&list->spinlock,flags);
+       
+}      /* end of n_hdlc_buf_put() */
+
+/**
+ * n_hdlc_buf_get - remove and return an HDLC buffer from list
+ * @list - pointer to HDLC buffer list
+ * 
+ * Remove and return an HDLC buffer from the head of the specified HDLC buffer
+ * list.
+ * Returns a pointer to HDLC buffer if available, otherwise %NULL.
+ */
+static struct n_hdlc_buf* n_hdlc_buf_get(struct n_hdlc_buf_list *list)
+{
+       unsigned long flags;
+       struct n_hdlc_buf *buf;
+       spin_lock_irqsave(&list->spinlock,flags);
+       
+       buf = list->head;
+       if (buf) {
+               list->head = buf->link;
+               (list->count)--;
+       }
+       if (!list->head)
+               list->tail = NULL;
+       
+       spin_unlock_irqrestore(&list->spinlock,flags);
+       return buf;
+       
+}      /* end of n_hdlc_buf_get() */
+
+static char hdlc_banner[] __initdata =
+       KERN_INFO "HDLC line discipline maxframe=%u\n";
+static char hdlc_register_ok[] __initdata =
+       KERN_INFO "N_HDLC line discipline registered.\n";
+static char hdlc_register_fail[] __initdata =
+       KERN_ERR "error registering line discipline: %d\n";
+static char hdlc_init_fail[] __initdata =
+       KERN_INFO "N_HDLC: init failure %d\n";
+
+static int __init n_hdlc_init(void)
+{
+       int status;
+
+       /* range check maxframe arg */
+       if (maxframe < 4096)
+               maxframe = 4096;
+       else if (maxframe > 65535)
+               maxframe = 65535;
+
+       printk(hdlc_banner, maxframe);
+
+       status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc);
+       if (!status)
+               printk(hdlc_register_ok);
+       else
+               printk(hdlc_register_fail, status);
+
+       if (status)
+               printk(hdlc_init_fail, status);
+       return status;
+       
+}      /* end of init_module() */
+
+static char hdlc_unregister_ok[] __exitdata =
+       KERN_INFO "N_HDLC: line discipline unregistered\n";
+static char hdlc_unregister_fail[] __exitdata =
+       KERN_ERR "N_HDLC: can't unregister line discipline (err = %d)\n";
+
+static void __exit n_hdlc_exit(void)
+{
+       /* Release tty registration of line discipline */
+       int status = tty_unregister_ldisc(N_HDLC);
+
+       if (status)
+               printk(hdlc_unregister_fail, status);
+       else
+               printk(hdlc_unregister_ok);
+}
+
+module_init(n_hdlc_init);
+module_exit(n_hdlc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Paul Fulghum paulkf@microgate.com");
+module_param(debuglevel, int, 0);
+module_param(maxframe, int, 0);
+MODULE_ALIAS_LDISC(N_HDLC);
diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c
new file mode 100644 (file)
index 0000000..88dda0c
--- /dev/null
@@ -0,0 +1,1264 @@
+/* r3964 linediscipline for linux
+ *
+ * -----------------------------------------------------------
+ * Copyright by 
+ * Philips Automation Projects
+ * Kassel (Germany)
+ * -----------------------------------------------------------
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ *
+ * Author:
+ * L. Haag
+ *
+ * $Log: n_r3964.c,v $
+ * Revision 1.10  2001/03/18 13:02:24  dwmw2
+ * Fix timer usage, use spinlocks properly.
+ *
+ * Revision 1.9  2001/03/18 12:52:14  dwmw2
+ * Merge changes in 2.4.2
+ *
+ * Revision 1.8  2000/03/23 14:14:54  dwmw2
+ * Fix race in sleeping in r3964_read()
+ *
+ * Revision 1.7  1999/28/08 11:41:50  dwmw2
+ * Port to 2.3 kernel
+ *
+ * Revision 1.6  1998/09/30 00:40:40  dwmw2
+ * Fixed compilation on 2.0.x kernels
+ * Updated to newly registered tty-ldisc number 9
+ *
+ * Revision 1.5  1998/09/04 21:57:36  dwmw2
+ * Signal handling bug fixes, port to 2.1.x.
+ *
+ * Revision 1.4  1998/04/02 20:26:59  lhaag
+ * select, blocking, ...
+ *
+ * Revision 1.3  1998/02/12 18:58:43  root
+ * fixed some memory leaks
+ * calculation of checksum characters
+ *
+ * Revision 1.2  1998/02/07 13:03:34  root
+ * ioctl read_telegram
+ *
+ * Revision 1.1  1998/02/06 19:21:03  root
+ * Initial revision
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/string.h>      /* used in new tty drivers */
+#include <linux/signal.h>      /* used in new tty drivers */
+#include <linux/ioctl.h>
+#include <linux/n_r3964.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+
+/*#define DEBUG_QUEUE*/
+
+/* Log successful handshake and protocol operations  */
+/*#define DEBUG_PROTO_S*/
+
+/* Log handshake and protocol errors: */
+/*#define DEBUG_PROTO_E*/
+
+/* Log Linediscipline operations (open, close, read, write...): */
+/*#define DEBUG_LDISC*/
+
+/* Log module and memory operations (init, cleanup; kmalloc, kfree): */
+/*#define DEBUG_MODUL*/
+
+/* Macro helpers for debug output: */
+#define TRACE(format, args...) printk("r3964: " format "\n" , ## args)
+
+#ifdef DEBUG_MODUL
+#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args)
+#else
+#define TRACE_M(fmt, arg...) do {} while (0)
+#endif
+#ifdef DEBUG_PROTO_S
+#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args)
+#else
+#define TRACE_PS(fmt, arg...) do {} while (0)
+#endif
+#ifdef DEBUG_PROTO_E
+#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args)
+#else
+#define TRACE_PE(fmt, arg...) do {} while (0)
+#endif
+#ifdef DEBUG_LDISC
+#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args)
+#else
+#define TRACE_L(fmt, arg...) do {} while (0)
+#endif
+#ifdef DEBUG_QUEUE
+#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args)
+#else
+#define TRACE_Q(fmt, arg...) do {} while (0)
+#endif
+static void add_tx_queue(struct r3964_info *, struct r3964_block_header *);
+static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code);
+static void put_char(struct r3964_info *pInfo, unsigned char ch);
+static void trigger_transmit(struct r3964_info *pInfo);
+static void retry_transmit(struct r3964_info *pInfo);
+static void transmit_block(struct r3964_info *pInfo);
+static void receive_char(struct r3964_info *pInfo, const unsigned char c);
+static void receive_error(struct r3964_info *pInfo, const char flag);
+static void on_timeout(unsigned long priv);
+static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg);
+static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
+               unsigned char __user * buf);
+static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
+               int error_code, struct r3964_block_header *pBlock);
+static struct r3964_message *remove_msg(struct r3964_info *pInfo,
+               struct r3964_client_info *pClient);
+static void remove_client_block(struct r3964_info *pInfo,
+               struct r3964_client_info *pClient);
+
+static int r3964_open(struct tty_struct *tty);
+static void r3964_close(struct tty_struct *tty);
+static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
+               unsigned char __user * buf, size_t nr);
+static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
+               const unsigned char *buf, size_t nr);
+static int r3964_ioctl(struct tty_struct *tty, struct file *file,
+               unsigned int cmd, unsigned long arg);
+static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old);
+static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
+               struct poll_table_struct *wait);
+static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+               char *fp, int count);
+
+static struct tty_ldisc_ops tty_ldisc_N_R3964 = {
+       .owner = THIS_MODULE,
+       .magic = TTY_LDISC_MAGIC,
+       .name = "R3964",
+       .open = r3964_open,
+       .close = r3964_close,
+       .read = r3964_read,
+       .write = r3964_write,
+       .ioctl = r3964_ioctl,
+       .set_termios = r3964_set_termios,
+       .poll = r3964_poll,
+       .receive_buf = r3964_receive_buf,
+};
+
+static void dump_block(const unsigned char *block, unsigned int length)
+{
+       unsigned int i, j;
+       char linebuf[16 * 3 + 1];
+
+       for (i = 0; i < length; i += 16) {
+               for (j = 0; (j < 16) && (j + i < length); j++) {
+                       sprintf(linebuf + 3 * j, "%02x ", block[i + j]);
+               }
+               linebuf[3 * j] = '\0';
+               TRACE_PS("%s", linebuf);
+       }
+}
+
+/*************************************************************
+ * Driver initialisation
+ *************************************************************/
+
+/*************************************************************
+ * Module support routines
+ *************************************************************/
+
+static void __exit r3964_exit(void)
+{
+       int status;
+
+       TRACE_M("cleanup_module()");
+
+       status = tty_unregister_ldisc(N_R3964);
+
+       if (status != 0) {
+               printk(KERN_ERR "r3964: error unregistering linediscipline: "
+                               "%d\n", status);
+       } else {
+               TRACE_L("linediscipline successfully unregistered");
+       }
+}
+
+static int __init r3964_init(void)
+{
+       int status;
+
+       printk("r3964: Philips r3964 Driver $Revision: 1.10 $\n");
+
+       /*
+        * Register the tty line discipline
+        */
+
+       status = tty_register_ldisc(N_R3964, &tty_ldisc_N_R3964);
+       if (status == 0) {
+               TRACE_L("line discipline %d registered", N_R3964);
+               TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags,
+                       tty_ldisc_N_R3964.num);
+               TRACE_L("open=%p", tty_ldisc_N_R3964.open);
+               TRACE_L("tty_ldisc_N_R3964 = %p", &tty_ldisc_N_R3964);
+       } else {
+               printk(KERN_ERR "r3964: error registering line discipline: "
+                               "%d\n", status);
+       }
+       return status;
+}
+
+module_init(r3964_init);
+module_exit(r3964_exit);
+
+/*************************************************************
+ * Protocol implementation routines
+ *************************************************************/
+
+static void add_tx_queue(struct r3964_info *pInfo,
+                        struct r3964_block_header *pHeader)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pInfo->lock, flags);
+
+       pHeader->next = NULL;
+
+       if (pInfo->tx_last == NULL) {
+               pInfo->tx_first = pInfo->tx_last = pHeader;
+       } else {
+               pInfo->tx_last->next = pHeader;
+               pInfo->tx_last = pHeader;
+       }
+
+       spin_unlock_irqrestore(&pInfo->lock, flags);
+
+       TRACE_Q("add_tx_queue %p, length %d, tx_first = %p",
+               pHeader, pHeader->length, pInfo->tx_first);
+}
+
+static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code)
+{
+       struct r3964_block_header *pHeader;
+       unsigned long flags;
+#ifdef DEBUG_QUEUE
+       struct r3964_block_header *pDump;
+#endif
+
+       pHeader = pInfo->tx_first;
+
+       if (pHeader == NULL)
+               return;
+
+#ifdef DEBUG_QUEUE
+       printk("r3964: remove_from_tx_queue: %p, length %u - ",
+               pHeader, pHeader->length);
+       for (pDump = pHeader; pDump; pDump = pDump->next)
+               printk("%p ", pDump);
+       printk("\n");
+#endif
+
+       if (pHeader->owner) {
+               if (error_code) {
+                       add_msg(pHeader->owner, R3964_MSG_ACK, 0,
+                               error_code, NULL);
+               } else {
+                       add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length,
+                               error_code, NULL);
+               }
+               wake_up_interruptible(&pInfo->read_wait);
+       }
+
+       spin_lock_irqsave(&pInfo->lock, flags);
+
+       pInfo->tx_first = pHeader->next;
+       if (pInfo->tx_first == NULL) {
+               pInfo->tx_last = NULL;
+       }
+
+       spin_unlock_irqrestore(&pInfo->lock, flags);
+
+       kfree(pHeader);
+       TRACE_M("remove_from_tx_queue - kfree %p", pHeader);
+
+       TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p",
+               pInfo->tx_first, pInfo->tx_last);
+}
+
+static void add_rx_queue(struct r3964_info *pInfo,
+                        struct r3964_block_header *pHeader)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pInfo->lock, flags);
+
+       pHeader->next = NULL;
+
+       if (pInfo->rx_last == NULL) {
+               pInfo->rx_first = pInfo->rx_last = pHeader;
+       } else {
+               pInfo->rx_last->next = pHeader;
+               pInfo->rx_last = pHeader;
+       }
+       pInfo->blocks_in_rx_queue++;
+
+       spin_unlock_irqrestore(&pInfo->lock, flags);
+
+       TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d",
+               pHeader, pHeader->length,
+               pInfo->rx_first, pInfo->blocks_in_rx_queue);
+}
+
+static void remove_from_rx_queue(struct r3964_info *pInfo,
+                                struct r3964_block_header *pHeader)
+{
+       unsigned long flags;
+       struct r3964_block_header *pFind;
+
+       if (pHeader == NULL)
+               return;
+
+       TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
+               pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
+       TRACE_Q("remove_from_rx_queue: %p, length %u",
+               pHeader, pHeader->length);
+
+       spin_lock_irqsave(&pInfo->lock, flags);
+
+       if (pInfo->rx_first == pHeader) {
+               /* Remove the first block in the linked list: */
+               pInfo->rx_first = pHeader->next;
+
+               if (pInfo->rx_first == NULL) {
+                       pInfo->rx_last = NULL;
+               }
+               pInfo->blocks_in_rx_queue--;
+       } else {
+               /* Find block to remove: */
+               for (pFind = pInfo->rx_first; pFind; pFind = pFind->next) {
+                       if (pFind->next == pHeader) {
+                               /* Got it. */
+                               pFind->next = pHeader->next;
+                               pInfo->blocks_in_rx_queue--;
+                               if (pFind->next == NULL) {
+                                       /* Oh, removed the last one! */
+                                       pInfo->rx_last = pFind;
+                               }
+                               break;
+                       }
+               }
+       }
+
+       spin_unlock_irqrestore(&pInfo->lock, flags);
+
+       kfree(pHeader);
+       TRACE_M("remove_from_rx_queue - kfree %p", pHeader);
+
+       TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
+               pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
+}
+
+static void put_char(struct r3964_info *pInfo, unsigned char ch)
+{
+       struct tty_struct *tty = pInfo->tty;
+       /* FIXME: put_char should not be called from an IRQ */
+       tty_put_char(tty, ch);
+       pInfo->bcc ^= ch;
+}
+
+static void flush(struct r3964_info *pInfo)
+{
+       struct tty_struct *tty = pInfo->tty;
+
+       if (tty == NULL || tty->ops->flush_chars == NULL)
+               return;
+       tty->ops->flush_chars(tty);
+}
+
+static void trigger_transmit(struct r3964_info *pInfo)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&pInfo->lock, flags);
+
+       if ((pInfo->state == R3964_IDLE) && (pInfo->tx_first != NULL)) {
+               pInfo->state = R3964_TX_REQUEST;
+               pInfo->nRetry = 0;
+               pInfo->flags &= ~R3964_ERROR;
+               mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
+
+               spin_unlock_irqrestore(&pInfo->lock, flags);
+
+               TRACE_PS("trigger_transmit - sent STX");
+
+               put_char(pInfo, STX);
+               flush(pInfo);
+
+               pInfo->bcc = 0;
+       } else {
+               spin_unlock_irqrestore(&pInfo->lock, flags);
+       }
+}
+
+static void retry_transmit(struct r3964_info *pInfo)
+{
+       if (pInfo->nRetry < R3964_MAX_RETRIES) {
+               TRACE_PE("transmission failed. Retry #%d", pInfo->nRetry);
+               pInfo->bcc = 0;
+               put_char(pInfo, STX);
+               flush(pInfo);
+               pInfo->state = R3964_TX_REQUEST;
+               pInfo->nRetry++;
+               mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
+       } else {
+               TRACE_PE("transmission failed after %d retries",
+                        R3964_MAX_RETRIES);
+
+               remove_from_tx_queue(pInfo, R3964_TX_FAIL);
+
+               put_char(pInfo, NAK);
+               flush(pInfo);
+               pInfo->state = R3964_IDLE;
+
+               trigger_transmit(pInfo);
+       }
+}
+
+static void transmit_block(struct r3964_info *pInfo)
+{
+       struct tty_struct *tty = pInfo->tty;
+       struct r3964_block_header *pBlock = pInfo->tx_first;
+       int room = 0;
+
+       if (tty == NULL || pBlock == NULL) {
+               return;
+       }
+
+       room = tty_write_room(tty);
+
+       TRACE_PS("transmit_block %p, room %d, length %d",
+                pBlock, room, pBlock->length);
+
+       while (pInfo->tx_position < pBlock->length) {
+               if (room < 2)
+                       break;
+
+               if (pBlock->data[pInfo->tx_position] == DLE) {
+                       /* send additional DLE char: */
+                       put_char(pInfo, DLE);
+               }
+               put_char(pInfo, pBlock->data[pInfo->tx_position++]);
+
+               room--;
+       }
+
+       if ((pInfo->tx_position == pBlock->length) && (room >= 3)) {
+               put_char(pInfo, DLE);
+               put_char(pInfo, ETX);
+               if (pInfo->flags & R3964_BCC) {
+                       put_char(pInfo, pInfo->bcc);
+               }
+               pInfo->state = R3964_WAIT_FOR_TX_ACK;
+               mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
+       }
+       flush(pInfo);
+}
+
+static void on_receive_block(struct r3964_info *pInfo)
+{
+       unsigned int length;
+       struct r3964_client_info *pClient;
+       struct r3964_block_header *pBlock;
+
+       length = pInfo->rx_position;
+
+       /* compare byte checksum characters: */
+       if (pInfo->flags & R3964_BCC) {
+               if (pInfo->bcc != pInfo->last_rx) {
+                       TRACE_PE("checksum error - got %x but expected %x",
+                                pInfo->last_rx, pInfo->bcc);
+                       pInfo->flags |= R3964_CHECKSUM;
+               }
+       }
+
+       /* check for errors (parity, overrun,...): */
+       if (pInfo->flags & R3964_ERROR) {
+               TRACE_PE("on_receive_block - transmission failed error %x",
+                        pInfo->flags & R3964_ERROR);
+
+               put_char(pInfo, NAK);
+               flush(pInfo);
+               if (pInfo->nRetry < R3964_MAX_RETRIES) {
+                       pInfo->state = R3964_WAIT_FOR_RX_REPEAT;
+                       pInfo->nRetry++;
+                       mod_timer(&pInfo->tmr, jiffies + R3964_TO_RX_PANIC);
+               } else {
+                       TRACE_PE("on_receive_block - failed after max retries");
+                       pInfo->state = R3964_IDLE;
+               }
+               return;
+       }
+
+       /* received block; submit DLE: */
+       put_char(pInfo, DLE);
+       flush(pInfo);
+       del_timer_sync(&pInfo->tmr);
+       TRACE_PS(" rx success: got %d chars", length);
+
+       /* prepare struct r3964_block_header: */
+       pBlock = kmalloc(length + sizeof(struct r3964_block_header),
+                       GFP_KERNEL);
+       TRACE_M("on_receive_block - kmalloc %p", pBlock);
+
+       if (pBlock == NULL)
+               return;
+
+       pBlock->length = length;
+       pBlock->data = ((unsigned char *)pBlock) +
+                       sizeof(struct r3964_block_header);
+       pBlock->locks = 0;
+       pBlock->next = NULL;
+       pBlock->owner = NULL;
+
+       memcpy(pBlock->data, pInfo->rx_buf, length);
+
+       /* queue block into rx_queue: */
+       add_rx_queue(pInfo, pBlock);
+
+       /* notify attached client processes: */
+       for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
+               if (pClient->sig_flags & R3964_SIG_DATA) {
+                       add_msg(pClient, R3964_MSG_DATA, length, R3964_OK,
+                               pBlock);
+               }
+       }
+       wake_up_interruptible(&pInfo->read_wait);
+
+       pInfo->state = R3964_IDLE;
+
+       trigger_transmit(pInfo);
+}
+
+static void receive_char(struct r3964_info *pInfo, const unsigned char c)
+{
+       switch (pInfo->state) {
+       case R3964_TX_REQUEST:
+               if (c == DLE) {
+                       TRACE_PS("TX_REQUEST - got DLE");
+
+                       pInfo->state = R3964_TRANSMITTING;
+                       pInfo->tx_position = 0;
+
+                       transmit_block(pInfo);
+               } else if (c == STX) {
+                       if (pInfo->nRetry == 0) {
+                               TRACE_PE("TX_REQUEST - init conflict");
+                               if (pInfo->priority == R3964_SLAVE) {
+                                       goto start_receiving;
+                               }
+                       } else {
+                               TRACE_PE("TX_REQUEST - secondary init "
+                                       "conflict!? Switching to SLAVE mode "
+                                       "for next rx.");
+                               goto start_receiving;
+                       }
+               } else {
+                       TRACE_PE("TX_REQUEST - char != DLE: %x", c);
+                       retry_transmit(pInfo);
+               }
+               break;
+       case R3964_TRANSMITTING:
+               if (c == NAK) {
+                       TRACE_PE("TRANSMITTING - got NAK");
+                       retry_transmit(pInfo);
+               } else {
+                       TRACE_PE("TRANSMITTING - got invalid char");
+
+                       pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY;
+                       mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
+               }
+               break;
+       case R3964_WAIT_FOR_TX_ACK:
+               if (c == DLE) {
+                       TRACE_PS("WAIT_FOR_TX_ACK - got DLE");
+                       remove_from_tx_queue(pInfo, R3964_OK);
+
+                       pInfo->state = R3964_IDLE;
+                       trigger_transmit(pInfo);
+               } else {
+                       retry_transmit(pInfo);
+               }
+               break;
+       case R3964_WAIT_FOR_RX_REPEAT:
+               /* FALLTHROUGH */
+       case R3964_IDLE:
+               if (c == STX) {
+                       /* Prevent rx_queue from overflow: */
+                       if (pInfo->blocks_in_rx_queue >=
+                           R3964_MAX_BLOCKS_IN_RX_QUEUE) {
+                               TRACE_PE("IDLE - got STX but no space in "
+                                               "rx_queue!");
+                               pInfo->state = R3964_WAIT_FOR_RX_BUF;
+                               mod_timer(&pInfo->tmr,
+                                         jiffies + R3964_TO_NO_BUF);
+                               break;
+                       }
+start_receiving:
+                       /* Ok, start receiving: */
+                       TRACE_PS("IDLE - got STX");
+                       pInfo->rx_position = 0;
+                       pInfo->last_rx = 0;
+                       pInfo->flags &= ~R3964_ERROR;
+                       pInfo->state = R3964_RECEIVING;
+                       mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
+                       pInfo->nRetry = 0;
+                       put_char(pInfo, DLE);
+                       flush(pInfo);
+                       pInfo->bcc = 0;
+               }
+               break;
+       case R3964_RECEIVING:
+               if (pInfo->rx_position < RX_BUF_SIZE) {
+                       pInfo->bcc ^= c;
+
+                       if (c == DLE) {
+                               if (pInfo->last_rx == DLE) {
+                                       pInfo->last_rx = 0;
+                                       goto char_to_buf;
+                               }
+                               pInfo->last_rx = DLE;
+                               break;
+                       } else if ((c == ETX) && (pInfo->last_rx == DLE)) {
+                               if (pInfo->flags & R3964_BCC) {
+                                       pInfo->state = R3964_WAIT_FOR_BCC;
+                                       mod_timer(&pInfo->tmr,
+                                                 jiffies + R3964_TO_ZVZ);
+                               } else {
+                                       on_receive_block(pInfo);
+                               }
+                       } else {
+                               pInfo->last_rx = c;
+char_to_buf:
+                               pInfo->rx_buf[pInfo->rx_position++] = c;
+                               mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
+                       }
+               }
+               /* else: overflow-msg? BUF_SIZE>MTU; should not happen? */
+               break;
+       case R3964_WAIT_FOR_BCC:
+               pInfo->last_rx = c;
+               on_receive_block(pInfo);
+               break;
+       }
+}
+
+static void receive_error(struct r3964_info *pInfo, const char flag)
+{
+       switch (flag) {
+       case TTY_NORMAL:
+               break;
+       case TTY_BREAK:
+               TRACE_PE("received break");
+               pInfo->flags |= R3964_BREAK;
+               break;
+       case TTY_PARITY:
+               TRACE_PE("parity error");
+               pInfo->flags |= R3964_PARITY;
+               break;
+       case TTY_FRAME:
+               TRACE_PE("frame error");
+               pInfo->flags |= R3964_FRAME;
+               break;
+       case TTY_OVERRUN:
+               TRACE_PE("frame overrun");
+               pInfo->flags |= R3964_OVERRUN;
+               break;
+       default:
+               TRACE_PE("receive_error - unknown flag %d", flag);
+               pInfo->flags |= R3964_UNKNOWN;
+               break;
+       }
+}
+
+static void on_timeout(unsigned long priv)
+{
+       struct r3964_info *pInfo = (void *)priv;
+
+       switch (pInfo->state) {
+       case R3964_TX_REQUEST:
+               TRACE_PE("TX_REQUEST - timeout");
+               retry_transmit(pInfo);
+               break;
+       case R3964_WAIT_ZVZ_BEFORE_TX_RETRY:
+               put_char(pInfo, NAK);
+               flush(pInfo);
+               retry_transmit(pInfo);
+               break;
+       case R3964_WAIT_FOR_TX_ACK:
+               TRACE_PE("WAIT_FOR_TX_ACK - timeout");
+               retry_transmit(pInfo);
+               break;
+       case R3964_WAIT_FOR_RX_BUF:
+               TRACE_PE("WAIT_FOR_RX_BUF - timeout");
+               put_char(pInfo, NAK);
+               flush(pInfo);
+               pInfo->state = R3964_IDLE;
+               break;
+       case R3964_RECEIVING:
+               TRACE_PE("RECEIVING - timeout after %d chars",
+                        pInfo->rx_position);
+               put_char(pInfo, NAK);
+               flush(pInfo);
+               pInfo->state = R3964_IDLE;
+               break;
+       case R3964_WAIT_FOR_RX_REPEAT:
+               TRACE_PE("WAIT_FOR_RX_REPEAT - timeout");
+               pInfo->state = R3964_IDLE;
+               break;
+       case R3964_WAIT_FOR_BCC:
+               TRACE_PE("WAIT_FOR_BCC - timeout");
+               put_char(pInfo, NAK);
+               flush(pInfo);
+               pInfo->state = R3964_IDLE;
+               break;
+       }
+}
+
+static struct r3964_client_info *findClient(struct r3964_info *pInfo,
+               struct pid *pid)
+{
+       struct r3964_client_info *pClient;
+
+       for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
+               if (pClient->pid == pid) {
+                       return pClient;
+               }
+       }
+       return NULL;
+}
+
+static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg)
+{
+       struct r3964_client_info *pClient;
+       struct r3964_client_info **ppClient;
+       struct r3964_message *pMsg;
+
+       if ((arg & R3964_SIG_ALL) == 0) {
+               /* Remove client from client list */
+               for (ppClient = &pInfo->firstClient; *ppClient;
+                    ppClient = &(*ppClient)->next) {
+                       pClient = *ppClient;
+
+                       if (pClient->pid == pid) {
+                               TRACE_PS("removing client %d from client list",
+                                        pid_nr(pid));
+                               *ppClient = pClient->next;
+                               while (pClient->msg_count) {
+                                       pMsg = remove_msg(pInfo, pClient);
+                                       if (pMsg) {
+                                               kfree(pMsg);
+                                               TRACE_M("enable_signals - msg "
+                                                       "kfree %p", pMsg);
+                                       }
+                               }
+                               put_pid(pClient->pid);
+                               kfree(pClient);
+                               TRACE_M("enable_signals - kfree %p", pClient);
+                               return 0;
+                       }
+               }
+               return -EINVAL;
+       } else {
+               pClient = findClient(pInfo, pid);
+               if (pClient) {
+                       /* update signal options */
+                       pClient->sig_flags = arg;
+               } else {
+                       /* add client to client list */
+                       pClient = kmalloc(sizeof(struct r3964_client_info),
+                                       GFP_KERNEL);
+                       TRACE_M("enable_signals - kmalloc %p", pClient);
+                       if (pClient == NULL)
+                               return -ENOMEM;
+
+                       TRACE_PS("add client %d to client list", pid_nr(pid));
+                       spin_lock_init(&pClient->lock);
+                       pClient->sig_flags = arg;
+                       pClient->pid = get_pid(pid);
+                       pClient->next = pInfo->firstClient;
+                       pClient->first_msg = NULL;
+                       pClient->last_msg = NULL;
+                       pClient->next_block_to_read = NULL;
+                       pClient->msg_count = 0;
+                       pInfo->firstClient = pClient;
+               }
+       }
+
+       return 0;
+}
+
+static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
+                        unsigned char __user * buf)
+{
+       struct r3964_client_info *pClient;
+       struct r3964_block_header *block;
+
+       if (!buf) {
+               return -EINVAL;
+       }
+
+       pClient = findClient(pInfo, pid);
+       if (pClient == NULL) {
+               return -EINVAL;
+       }
+
+       block = pClient->next_block_to_read;
+       if (!block) {
+               return 0;
+       } else {
+               if (copy_to_user(buf, block->data, block->length))
+                       return -EFAULT;
+
+               remove_client_block(pInfo, pClient);
+               return block->length;
+       }
+
+       return -EINVAL;
+}
+
+static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
+               int error_code, struct r3964_block_header *pBlock)
+{
+       struct r3964_message *pMsg;
+       unsigned long flags;
+
+       if (pClient->msg_count < R3964_MAX_MSG_COUNT - 1) {
+queue_the_message:
+
+               pMsg = kmalloc(sizeof(struct r3964_message),
+                               error_code ? GFP_ATOMIC : GFP_KERNEL);
+               TRACE_M("add_msg - kmalloc %p", pMsg);
+               if (pMsg == NULL) {
+                       return;
+               }
+
+               spin_lock_irqsave(&pClient->lock, flags);
+
+               pMsg->msg_id = msg_id;
+               pMsg->arg = arg;
+               pMsg->error_code = error_code;
+               pMsg->block = pBlock;
+               pMsg->next = NULL;
+
+               if (pClient->last_msg == NULL) {
+                       pClient->first_msg = pClient->last_msg = pMsg;
+               } else {
+                       pClient->last_msg->next = pMsg;
+                       pClient->last_msg = pMsg;
+               }
+
+               pClient->msg_count++;
+
+               if (pBlock != NULL) {
+                       pBlock->locks++;
+               }
+               spin_unlock_irqrestore(&pClient->lock, flags);
+       } else {
+               if ((pClient->last_msg->msg_id == R3964_MSG_ACK)
+                   && (pClient->last_msg->error_code == R3964_OVERFLOW)) {
+                       pClient->last_msg->arg++;
+                       TRACE_PE("add_msg - inc prev OVERFLOW-msg");
+               } else {
+                       msg_id = R3964_MSG_ACK;
+                       arg = 0;
+                       error_code = R3964_OVERFLOW;
+                       pBlock = NULL;
+                       TRACE_PE("add_msg - queue OVERFLOW-msg");
+                       goto queue_the_message;
+               }
+       }
+       /* Send SIGIO signal to client process: */
+       if (pClient->sig_flags & R3964_USE_SIGIO) {
+               kill_pid(pClient->pid, SIGIO, 1);
+       }
+}
+
+static struct r3964_message *remove_msg(struct r3964_info *pInfo,
+                                       struct r3964_client_info *pClient)
+{
+       struct r3964_message *pMsg = NULL;
+       unsigned long flags;
+
+       if (pClient->first_msg) {
+               spin_lock_irqsave(&pClient->lock, flags);
+
+               pMsg = pClient->first_msg;
+               pClient->first_msg = pMsg->next;
+               if (pClient->first_msg == NULL) {
+                       pClient->last_msg = NULL;
+               }
+
+               pClient->msg_count--;
+               if (pMsg->block) {
+                       remove_client_block(pInfo, pClient);
+                       pClient->next_block_to_read = pMsg->block;
+               }
+               spin_unlock_irqrestore(&pClient->lock, flags);
+       }
+       return pMsg;
+}
+
+static void remove_client_block(struct r3964_info *pInfo,
+                               struct r3964_client_info *pClient)
+{
+       struct r3964_block_header *block;
+
+       TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid));
+
+       block = pClient->next_block_to_read;
+       if (block) {
+               block->locks--;
+               if (block->locks == 0) {
+                       remove_from_rx_queue(pInfo, block);
+               }
+       }
+       pClient->next_block_to_read = NULL;
+}
+
+/*************************************************************
+ * Line discipline routines
+ *************************************************************/
+
+static int r3964_open(struct tty_struct *tty)
+{
+       struct r3964_info *pInfo;
+
+       TRACE_L("open");
+       TRACE_L("tty=%p, PID=%d, disc_data=%p",
+               tty, current->pid, tty->disc_data);
+
+       pInfo = kmalloc(sizeof(struct r3964_info), GFP_KERNEL);
+       TRACE_M("r3964_open - info kmalloc %p", pInfo);
+
+       if (!pInfo) {
+               printk(KERN_ERR "r3964: failed to alloc info structure\n");
+               return -ENOMEM;
+       }
+
+       pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL);
+       TRACE_M("r3964_open - rx_buf kmalloc %p", pInfo->rx_buf);
+
+       if (!pInfo->rx_buf) {
+               printk(KERN_ERR "r3964: failed to alloc receive buffer\n");
+               kfree(pInfo);
+               TRACE_M("r3964_open - info kfree %p", pInfo);
+               return -ENOMEM;
+       }
+
+       pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL);
+       TRACE_M("r3964_open - tx_buf kmalloc %p", pInfo->tx_buf);
+
+       if (!pInfo->tx_buf) {
+               printk(KERN_ERR "r3964: failed to alloc transmit buffer\n");
+               kfree(pInfo->rx_buf);
+               TRACE_M("r3964_open - rx_buf kfree %p", pInfo->rx_buf);
+               kfree(pInfo);
+               TRACE_M("r3964_open - info kfree %p", pInfo);
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&pInfo->lock);
+       pInfo->tty = tty;
+       init_waitqueue_head(&pInfo->read_wait);
+       pInfo->priority = R3964_MASTER;
+       pInfo->rx_first = pInfo->rx_last = NULL;
+       pInfo->tx_first = pInfo->tx_last = NULL;
+       pInfo->rx_position = 0;
+       pInfo->tx_position = 0;
+       pInfo->last_rx = 0;
+       pInfo->blocks_in_rx_queue = 0;
+       pInfo->firstClient = NULL;
+       pInfo->state = R3964_IDLE;
+       pInfo->flags = R3964_DEBUG;
+       pInfo->nRetry = 0;
+
+       tty->disc_data = pInfo;
+       tty->receive_room = 65536;
+
+       setup_timer(&pInfo->tmr, on_timeout, (unsigned long)pInfo);
+
+       return 0;
+}
+
+static void r3964_close(struct tty_struct *tty)
+{
+       struct r3964_info *pInfo = tty->disc_data;
+       struct r3964_client_info *pClient, *pNext;
+       struct r3964_message *pMsg;
+       struct r3964_block_header *pHeader, *pNextHeader;
+       unsigned long flags;
+
+       TRACE_L("close");
+
+       /*
+        * Make sure that our task queue isn't activated.  If it
+        * is, take it out of the linked list.
+        */
+       del_timer_sync(&pInfo->tmr);
+
+       /* Remove client-structs and message queues: */
+       pClient = pInfo->firstClient;
+       while (pClient) {
+               pNext = pClient->next;
+               while (pClient->msg_count) {
+                       pMsg = remove_msg(pInfo, pClient);
+                       if (pMsg) {
+                               kfree(pMsg);
+                               TRACE_M("r3964_close - msg kfree %p", pMsg);
+                       }
+               }
+               put_pid(pClient->pid);
+               kfree(pClient);
+               TRACE_M("r3964_close - client kfree %p", pClient);
+               pClient = pNext;
+       }
+       /* Remove jobs from tx_queue: */
+       spin_lock_irqsave(&pInfo->lock, flags);
+       pHeader = pInfo->tx_first;
+       pInfo->tx_first = pInfo->tx_last = NULL;
+       spin_unlock_irqrestore(&pInfo->lock, flags);
+
+       while (pHeader) {
+               pNextHeader = pHeader->next;
+               kfree(pHeader);
+               pHeader = pNextHeader;
+       }
+
+       /* Free buffers: */
+       wake_up_interruptible(&pInfo->read_wait);
+       kfree(pInfo->rx_buf);
+       TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf);
+       kfree(pInfo->tx_buf);
+       TRACE_M("r3964_close - tx_buf kfree %p", pInfo->tx_buf);
+       kfree(pInfo);
+       TRACE_M("r3964_close - info kfree %p", pInfo);
+}
+
+static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
+                         unsigned char __user * buf, size_t nr)
+{
+       struct r3964_info *pInfo = tty->disc_data;
+       struct r3964_client_info *pClient;
+       struct r3964_message *pMsg;
+       struct r3964_client_message theMsg;
+       int ret;
+
+       TRACE_L("read()");
+
+       tty_lock();
+
+       pClient = findClient(pInfo, task_pid(current));
+       if (pClient) {
+               pMsg = remove_msg(pInfo, pClient);
+               if (pMsg == NULL) {
+                       /* no messages available. */
+                       if (file->f_flags & O_NONBLOCK) {
+                               ret = -EAGAIN;
+                               goto unlock;
+                       }
+                       /* block until there is a message: */
+                       wait_event_interruptible_tty(pInfo->read_wait,
+                                       (pMsg = remove_msg(pInfo, pClient)));
+               }
+
+               /* If we still haven't got a message, we must have been signalled */
+
+               if (!pMsg) {
+                       ret = -EINTR;
+                       goto unlock;
+               }
+
+               /* deliver msg to client process: */
+               theMsg.msg_id = pMsg->msg_id;
+               theMsg.arg = pMsg->arg;
+               theMsg.error_code = pMsg->error_code;
+               ret = sizeof(struct r3964_client_message);
+
+               kfree(pMsg);
+               TRACE_M("r3964_read - msg kfree %p", pMsg);
+
+               if (copy_to_user(buf, &theMsg, ret)) {
+                       ret = -EFAULT;
+                       goto unlock;
+               }
+
+               TRACE_PS("read - return %d", ret);
+               goto unlock;
+       }
+       ret = -EPERM;
+unlock:
+       tty_unlock();
+       return ret;
+}
+
+static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
+                          const unsigned char *data, size_t count)
+{
+       struct r3964_info *pInfo = tty->disc_data;
+       struct r3964_block_header *pHeader;
+       struct r3964_client_info *pClient;
+       unsigned char *new_data;
+
+       TRACE_L("write request, %d characters", count);
+/* 
+ * Verify the pointers 
+ */
+
+       if (!pInfo)
+               return -EIO;
+
+/*
+ * Ensure that the caller does not wish to send too much.
+ */
+       if (count > R3964_MTU) {
+               if (pInfo->flags & R3964_DEBUG) {
+                       TRACE_L(KERN_WARNING "r3964_write: truncating user "
+                               "packet from %u to mtu %d", count, R3964_MTU);
+               }
+               count = R3964_MTU;
+       }
+/*
+ * Allocate a buffer for the data and copy it from the buffer with header prepended
+ */
+       new_data = kmalloc(count + sizeof(struct r3964_block_header),
+                       GFP_KERNEL);
+       TRACE_M("r3964_write - kmalloc %p", new_data);
+       if (new_data == NULL) {
+               if (pInfo->flags & R3964_DEBUG) {
+                       printk(KERN_ERR "r3964_write: no memory\n");
+               }
+               return -ENOSPC;
+       }
+
+       pHeader = (struct r3964_block_header *)new_data;
+       pHeader->data = new_data + sizeof(struct r3964_block_header);
+       pHeader->length = count;
+       pHeader->locks = 0;
+       pHeader->owner = NULL;
+
+       tty_lock();
+
+       pClient = findClient(pInfo, task_pid(current));
+       if (pClient) {
+               pHeader->owner = pClient;
+       }
+
+       memcpy(pHeader->data, data, count);     /* We already verified this */
+
+       if (pInfo->flags & R3964_DEBUG) {
+               dump_block(pHeader->data, count);
+       }
+
+/*
+ * Add buffer to transmit-queue:
+ */
+       add_tx_queue(pInfo, pHeader);
+       trigger_transmit(pInfo);
+
+       tty_unlock();
+
+       return 0;
+}
+
+static int r3964_ioctl(struct tty_struct *tty, struct file *file,
+               unsigned int cmd, unsigned long arg)
+{
+       struct r3964_info *pInfo = tty->disc_data;
+       if (pInfo == NULL)
+               return -EINVAL;
+       switch (cmd) {
+       case R3964_ENABLE_SIGNALS:
+               return enable_signals(pInfo, task_pid(current), arg);
+       case R3964_SETPRIORITY:
+               if (arg < R3964_MASTER || arg > R3964_SLAVE)
+                       return -EINVAL;
+               pInfo->priority = arg & 0xff;
+               return 0;
+       case R3964_USE_BCC:
+               if (arg)
+                       pInfo->flags |= R3964_BCC;
+               else
+                       pInfo->flags &= ~R3964_BCC;
+               return 0;
+       case R3964_READ_TELEGRAM:
+               return read_telegram(pInfo, task_pid(current),
+                               (unsigned char __user *)arg);
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old)
+{
+       TRACE_L("set_termios");
+}
+
+/* Called without the kernel lock held - fine */
+static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
+                       struct poll_table_struct *wait)
+{
+       struct r3964_info *pInfo = tty->disc_data;
+       struct r3964_client_info *pClient;
+       struct r3964_message *pMsg = NULL;
+       unsigned long flags;
+       int result = POLLOUT;
+
+       TRACE_L("POLL");
+
+       pClient = findClient(pInfo, task_pid(current));
+       if (pClient) {
+               poll_wait(file, &pInfo->read_wait, wait);
+               spin_lock_irqsave(&pInfo->lock, flags);
+               pMsg = pClient->first_msg;
+               spin_unlock_irqrestore(&pInfo->lock, flags);
+               if (pMsg)
+                       result |= POLLIN | POLLRDNORM;
+       } else {
+               result = -EINVAL;
+       }
+       return result;
+}
+
+static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                       char *fp, int count)
+{
+       struct r3964_info *pInfo = tty->disc_data;
+       const unsigned char *p;
+       char *f, flags = 0;
+       int i;
+
+       for (i = count, p = cp, f = fp; i; i--, p++) {
+               if (f)
+                       flags = *f++;
+               if (flags == TTY_NORMAL) {
+                       receive_char(pInfo, *p);
+               } else {
+                       receive_error(pInfo, flags);
+               }
+
+       }
+}
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_LDISC(N_R3964);
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
new file mode 100644 (file)
index 0000000..428f4fe
--- /dev/null
@@ -0,0 +1,2121 @@
+/*
+ * n_tty.c --- implements the N_TTY line discipline.
+ *
+ * This code used to be in tty_io.c, but things are getting hairy
+ * enough that it made sense to split things off.  (The N_TTY
+ * processing has changed so much that it's hardly recognizable,
+ * anyway...)
+ *
+ * Note that the open routine for N_TTY is guaranteed never to return
+ * an error.  This is because Linux will fall back to setting a line
+ * to N_TTY if it can not switch to any other line discipline.
+ *
+ * Written by Theodore Ts'o, Copyright 1994.
+ *
+ * This file also contains code originally written by Linus Torvalds,
+ * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994.
+ *
+ * This file may be redistributed under the terms of the GNU General Public
+ * License.
+ *
+ * Reduced memory usage for older ARM systems  - Russell King.
+ *
+ * 2000/01/20   Fixed SMP locking on put_tty_queue using bits of
+ *             the patch by Andrew J. Kroll <ag784@freenet.buffalo.edu>
+ *             who actually finally proved there really was a race.
+ *
+ * 2002/03/18   Implemented n_tty_wakeup to send SIGIO POLL_OUTs to
+ *             waiting writing processes-Sapan Bhatia <sapan@corewars.org>.
+ *             Also fixed a bug in BLOCKING mode where n_tty_write returns
+ *             EAGAIN
+ */
+
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/timer.h>
+#include <linux/ctype.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/bitops.h>
+#include <linux/audit.h>
+#include <linux/file.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+
+/* number of characters left in xmit buffer before select has we have room */
+#define WAKEUP_CHARS 256
+
+/*
+ * This defines the low- and high-watermarks for throttling and
+ * unthrottling the TTY driver.  These watermarks are used for
+ * controlling the space in the read buffer.
+ */
+#define TTY_THRESHOLD_THROTTLE         128 /* now based on remaining room */
+#define TTY_THRESHOLD_UNTHROTTLE       128
+
+/*
+ * Special byte codes used in the echo buffer to represent operations
+ * or special handling of characters.  Bytes in the echo buffer that
+ * are not part of such special blocks are treated as normal character
+ * codes.
+ */
+#define ECHO_OP_START 0xff
+#define ECHO_OP_MOVE_BACK_COL 0x80
+#define ECHO_OP_SET_CANON_COL 0x81
+#define ECHO_OP_ERASE_TAB 0x82
+
+static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
+                              unsigned char __user *ptr)
+{
+       tty_audit_add_data(tty, &x, 1);
+       return put_user(x, ptr);
+}
+
+/**
+ *     n_tty_set__room -       receive space
+ *     @tty: terminal
+ *
+ *     Called by the driver to find out how much data it is
+ *     permitted to feed to the line discipline without any being lost
+ *     and thus to manage flow control. Not serialized. Answers for the
+ *     "instant".
+ */
+
+static void n_tty_set_room(struct tty_struct *tty)
+{
+       /* tty->read_cnt is not read locked ? */
+       int     left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+
+       /*
+        * If we are doing input canonicalization, and there are no
+        * pending newlines, let characters through without limit, so
+        * that erase characters will be handled.  Other excess
+        * characters will be beeped.
+        */
+       if (left <= 0)
+               left = tty->icanon && !tty->canon_data;
+       tty->receive_room = left;
+}
+
+static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
+{
+       if (tty->read_cnt < N_TTY_BUF_SIZE) {
+               tty->read_buf[tty->read_head] = c;
+               tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1);
+               tty->read_cnt++;
+       }
+}
+
+/**
+ *     put_tty_queue           -       add character to tty
+ *     @c: character
+ *     @tty: tty device
+ *
+ *     Add a character to the tty read_buf queue. This is done under the
+ *     read_lock to serialize character addition and also to protect us
+ *     against parallel reads or flushes
+ */
+
+static void put_tty_queue(unsigned char c, struct tty_struct *tty)
+{
+       unsigned long flags;
+       /*
+        *      The problem of stomping on the buffers ends here.
+        *      Why didn't anyone see this one coming? --AJK
+       */
+       spin_lock_irqsave(&tty->read_lock, flags);
+       put_tty_queue_nolock(c, tty);
+       spin_unlock_irqrestore(&tty->read_lock, flags);
+}
+
+/**
+ *     check_unthrottle        -       allow new receive data
+ *     @tty; tty device
+ *
+ *     Check whether to call the driver unthrottle functions
+ *
+ *     Can sleep, may be called under the atomic_read_lock mutex but
+ *     this is not guaranteed.
+ */
+static void check_unthrottle(struct tty_struct *tty)
+{
+       if (tty->count)
+               tty_unthrottle(tty);
+}
+
+/**
+ *     reset_buffer_flags      -       reset buffer state
+ *     @tty: terminal to reset
+ *
+ *     Reset the read buffer counters, clear the flags,
+ *     and make sure the driver is unthrottled. Called
+ *     from n_tty_open() and n_tty_flush_buffer().
+ *
+ *     Locking: tty_read_lock for read fields.
+ */
+
+static void reset_buffer_flags(struct tty_struct *tty)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&tty->read_lock, flags);
+       tty->read_head = tty->read_tail = tty->read_cnt = 0;
+       spin_unlock_irqrestore(&tty->read_lock, flags);
+
+       mutex_lock(&tty->echo_lock);
+       tty->echo_pos = tty->echo_cnt = tty->echo_overrun = 0;
+       mutex_unlock(&tty->echo_lock);
+
+       tty->canon_head = tty->canon_data = tty->erasing = 0;
+       memset(&tty->read_flags, 0, sizeof tty->read_flags);
+       n_tty_set_room(tty);
+       check_unthrottle(tty);
+}
+
+/**
+ *     n_tty_flush_buffer      -       clean input queue
+ *     @tty:   terminal device
+ *
+ *     Flush the input buffer. Called when the line discipline is
+ *     being closed, when the tty layer wants the buffer flushed (eg
+ *     at hangup) or when the N_TTY line discipline internally has to
+ *     clean the pending queue (for example some signals).
+ *
+ *     Locking: ctrl_lock, read_lock.
+ */
+
+static void n_tty_flush_buffer(struct tty_struct *tty)
+{
+       unsigned long flags;
+       /* clear everything and unthrottle the driver */
+       reset_buffer_flags(tty);
+
+       if (!tty->link)
+               return;
+
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       if (tty->link->packet) {
+               tty->ctrl_status |= TIOCPKT_FLUSHREAD;
+               wake_up_interruptible(&tty->link->read_wait);
+       }
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+}
+
+/**
+ *     n_tty_chars_in_buffer   -       report available bytes
+ *     @tty: tty device
+ *
+ *     Report the number of characters buffered to be delivered to user
+ *     at this instant in time.
+ *
+ *     Locking: read_lock
+ */
+
+static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
+{
+       unsigned long flags;
+       ssize_t n = 0;
+
+       spin_lock_irqsave(&tty->read_lock, flags);
+       if (!tty->icanon) {
+               n = tty->read_cnt;
+       } else if (tty->canon_data) {
+               n = (tty->canon_head > tty->read_tail) ?
+                       tty->canon_head - tty->read_tail :
+                       tty->canon_head + (N_TTY_BUF_SIZE - tty->read_tail);
+       }
+       spin_unlock_irqrestore(&tty->read_lock, flags);
+       return n;
+}
+
+/**
+ *     is_utf8_continuation    -       utf8 multibyte check
+ *     @c: byte to check
+ *
+ *     Returns true if the utf8 character 'c' is a multibyte continuation
+ *     character. We use this to correctly compute the on screen size
+ *     of the character when printing
+ */
+
+static inline int is_utf8_continuation(unsigned char c)
+{
+       return (c & 0xc0) == 0x80;
+}
+
+/**
+ *     is_continuation         -       multibyte check
+ *     @c: byte to check
+ *
+ *     Returns true if the utf8 character 'c' is a multibyte continuation
+ *     character and the terminal is in unicode mode.
+ */
+
+static inline int is_continuation(unsigned char c, struct tty_struct *tty)
+{
+       return I_IUTF8(tty) && is_utf8_continuation(c);
+}
+
+/**
+ *     do_output_char                  -       output one character
+ *     @c: character (or partial unicode symbol)
+ *     @tty: terminal device
+ *     @space: space available in tty driver write buffer
+ *
+ *     This is a helper function that handles one output character
+ *     (including special characters like TAB, CR, LF, etc.),
+ *     doing OPOST processing and putting the results in the
+ *     tty driver's write buffer.
+ *
+ *     Note that Linux currently ignores TABDLY, CRDLY, VTDLY, FFDLY
+ *     and NLDLY.  They simply aren't relevant in the world today.
+ *     If you ever need them, add them here.
+ *
+ *     Returns the number of bytes of buffer space used or -1 if
+ *     no space left.
+ *
+ *     Locking: should be called under the output_lock to protect
+ *              the column state and space left in the buffer
+ */
+
+static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
+{
+       int     spaces;
+
+       if (!space)
+               return -1;
+
+       switch (c) {
+       case '\n':
+               if (O_ONLRET(tty))
+                       tty->column = 0;
+               if (O_ONLCR(tty)) {
+                       if (space < 2)
+                               return -1;
+                       tty->canon_column = tty->column = 0;
+                       tty->ops->write(tty, "\r\n", 2);
+                       return 2;
+               }
+               tty->canon_column = tty->column;
+               break;
+       case '\r':
+               if (O_ONOCR(tty) && tty->column == 0)
+                       return 0;
+               if (O_OCRNL(tty)) {
+                       c = '\n';
+                       if (O_ONLRET(tty))
+                               tty->canon_column = tty->column = 0;
+                       break;
+               }
+               tty->canon_column = tty->column = 0;
+               break;
+       case '\t':
+               spaces = 8 - (tty->column & 7);
+               if (O_TABDLY(tty) == XTABS) {
+                       if (space < spaces)
+                               return -1;
+                       tty->column += spaces;
+                       tty->ops->write(tty, "        ", spaces);
+                       return spaces;
+               }
+               tty->column += spaces;
+               break;
+       case '\b':
+               if (tty->column > 0)
+                       tty->column--;
+               break;
+       default:
+               if (!iscntrl(c)) {
+                       if (O_OLCUC(tty))
+                               c = toupper(c);
+                       if (!is_continuation(c, tty))
+                               tty->column++;
+               }
+               break;
+       }
+
+       tty_put_char(tty, c);
+       return 1;
+}
+
+/**
+ *     process_output                  -       output post processor
+ *     @c: character (or partial unicode symbol)
+ *     @tty: terminal device
+ *
+ *     Output one character with OPOST processing.
+ *     Returns -1 when the output device is full and the character
+ *     must be retried.
+ *
+ *     Locking: output_lock to protect column state and space left
+ *              (also, this is called from n_tty_write under the
+ *               tty layer write lock)
+ */
+
+static int process_output(unsigned char c, struct tty_struct *tty)
+{
+       int     space, retval;
+
+       mutex_lock(&tty->output_lock);
+
+       space = tty_write_room(tty);
+       retval = do_output_char(c, tty, space);
+
+       mutex_unlock(&tty->output_lock);
+       if (retval < 0)
+               return -1;
+       else
+               return 0;
+}
+
+/**
+ *     process_output_block            -       block post processor
+ *     @tty: terminal device
+ *     @buf: character buffer
+ *     @nr: number of bytes to output
+ *
+ *     Output a block of characters with OPOST processing.
+ *     Returns the number of characters output.
+ *
+ *     This path is used to speed up block console writes, among other
+ *     things when processing blocks of output data. It handles only
+ *     the simple cases normally found and helps to generate blocks of
+ *     symbols for the console driver and thus improve performance.
+ *
+ *     Locking: output_lock to protect column state and space left
+ *              (also, this is called from n_tty_write under the
+ *               tty layer write lock)
+ */
+
+static ssize_t process_output_block(struct tty_struct *tty,
+                                   const unsigned char *buf, unsigned int nr)
+{
+       int     space;
+       int     i;
+       const unsigned char *cp;
+
+       mutex_lock(&tty->output_lock);
+
+       space = tty_write_room(tty);
+       if (!space) {
+               mutex_unlock(&tty->output_lock);
+               return 0;
+       }
+       if (nr > space)
+               nr = space;
+
+       for (i = 0, cp = buf; i < nr; i++, cp++) {
+               unsigned char c = *cp;
+
+               switch (c) {
+               case '\n':
+                       if (O_ONLRET(tty))
+                               tty->column = 0;
+                       if (O_ONLCR(tty))
+                               goto break_out;
+                       tty->canon_column = tty->column;
+                       break;
+               case '\r':
+                       if (O_ONOCR(tty) && tty->column == 0)
+                               goto break_out;
+                       if (O_OCRNL(tty))
+                               goto break_out;
+                       tty->canon_column = tty->column = 0;
+                       break;
+               case '\t':
+                       goto break_out;
+               case '\b':
+                       if (tty->column > 0)
+                               tty->column--;
+                       break;
+               default:
+                       if (!iscntrl(c)) {
+                               if (O_OLCUC(tty))
+                                       goto break_out;
+                               if (!is_continuation(c, tty))
+                                       tty->column++;
+                       }
+                       break;
+               }
+       }
+break_out:
+       i = tty->ops->write(tty, buf, i);
+
+       mutex_unlock(&tty->output_lock);
+       return i;
+}
+
+/**
+ *     process_echoes  -       write pending echo characters
+ *     @tty: terminal device
+ *
+ *     Write previously buffered echo (and other ldisc-generated)
+ *     characters to the tty.
+ *
+ *     Characters generated by the ldisc (including echoes) need to
+ *     be buffered because the driver's write buffer can fill during
+ *     heavy program output.  Echoing straight to the driver will
+ *     often fail under these conditions, causing lost characters and
+ *     resulting mismatches of ldisc state information.
+ *
+ *     Since the ldisc state must represent the characters actually sent
+ *     to the driver at the time of the write, operations like certain
+ *     changes in column state are also saved in the buffer and executed
+ *     here.
+ *
+ *     A circular fifo buffer is used so that the most recent characters
+ *     are prioritized.  Also, when control characters are echoed with a
+ *     prefixed "^", the pair is treated atomically and thus not separated.
+ *
+ *     Locking: output_lock to protect column state and space left,
+ *              echo_lock to protect the echo buffer
+ */
+
+static void process_echoes(struct tty_struct *tty)
+{
+       int     space, nr;
+       unsigned char c;
+       unsigned char *cp, *buf_end;
+
+       if (!tty->echo_cnt)
+               return;
+
+       mutex_lock(&tty->output_lock);
+       mutex_lock(&tty->echo_lock);
+
+       space = tty_write_room(tty);
+
+       buf_end = tty->echo_buf + N_TTY_BUF_SIZE;
+       cp = tty->echo_buf + tty->echo_pos;
+       nr = tty->echo_cnt;
+       while (nr > 0) {
+               c = *cp;
+               if (c == ECHO_OP_START) {
+                       unsigned char op;
+                       unsigned char *opp;
+                       int no_space_left = 0;
+
+                       /*
+                        * If the buffer byte is the start of a multi-byte
+                        * operation, get the next byte, which is either the
+                        * op code or a control character value.
+                        */
+                       opp = cp + 1;
+                       if (opp == buf_end)
+                               opp -= N_TTY_BUF_SIZE;
+                       op = *opp;
+
+                       switch (op) {
+                               unsigned int num_chars, num_bs;
+
+                       case ECHO_OP_ERASE_TAB:
+                               if (++opp == buf_end)
+                                       opp -= N_TTY_BUF_SIZE;
+                               num_chars = *opp;
+
+                               /*
+                                * Determine how many columns to go back
+                                * in order to erase the tab.
+                                * This depends on the number of columns
+                                * used by other characters within the tab
+                                * area.  If this (modulo 8) count is from
+                                * the start of input rather than from a
+                                * previous tab, we offset by canon column.
+                                * Otherwise, tab spacing is normal.
+                                */
+                               if (!(num_chars & 0x80))
+                                       num_chars += tty->canon_column;
+                               num_bs = 8 - (num_chars & 7);
+
+                               if (num_bs > space) {
+                                       no_space_left = 1;
+                                       break;
+                               }
+                               space -= num_bs;
+                               while (num_bs--) {
+                                       tty_put_char(tty, '\b');
+                                       if (tty->column > 0)
+                                               tty->column--;
+                               }
+                               cp += 3;
+                               nr -= 3;
+                               break;
+
+                       case ECHO_OP_SET_CANON_COL:
+                               tty->canon_column = tty->column;
+                               cp += 2;
+                               nr -= 2;
+                               break;
+
+                       case ECHO_OP_MOVE_BACK_COL:
+                               if (tty->column > 0)
+                                       tty->column--;
+                               cp += 2;
+                               nr -= 2;
+                               break;
+
+                       case ECHO_OP_START:
+                               /* This is an escaped echo op start code */
+                               if (!space) {
+                                       no_space_left = 1;
+                                       break;
+                               }
+                               tty_put_char(tty, ECHO_OP_START);
+                               tty->column++;
+                               space--;
+                               cp += 2;
+                               nr -= 2;
+                               break;
+
+                       default:
+                               /*
+                                * If the op is not a special byte code,
+                                * it is a ctrl char tagged to be echoed
+                                * as "^X" (where X is the letter
+                                * representing the control char).
+                                * Note that we must ensure there is
+                                * enough space for the whole ctrl pair.
+                                *
+                                */
+                               if (space < 2) {
+                                       no_space_left = 1;
+                                       break;
+                               }
+                               tty_put_char(tty, '^');
+                               tty_put_char(tty, op ^ 0100);
+                               tty->column += 2;
+                               space -= 2;
+                               cp += 2;
+                               nr -= 2;
+                       }
+
+                       if (no_space_left)
+                               break;
+               } else {
+                       if (O_OPOST(tty) &&
+                           !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
+                               int retval = do_output_char(c, tty, space);
+                               if (retval < 0)
+                                       break;
+                               space -= retval;
+                       } else {
+                               if (!space)
+                                       break;
+                               tty_put_char(tty, c);
+                               space -= 1;
+                       }
+                       cp += 1;
+                       nr -= 1;
+               }
+
+               /* When end of circular buffer reached, wrap around */
+               if (cp >= buf_end)
+                       cp -= N_TTY_BUF_SIZE;
+       }
+
+       if (nr == 0) {
+               tty->echo_pos = 0;
+               tty->echo_cnt = 0;
+               tty->echo_overrun = 0;
+       } else {
+               int num_processed = tty->echo_cnt - nr;
+               tty->echo_pos += num_processed;
+               tty->echo_pos &= N_TTY_BUF_SIZE - 1;
+               tty->echo_cnt = nr;
+               if (num_processed > 0)
+                       tty->echo_overrun = 0;
+       }
+
+       mutex_unlock(&tty->echo_lock);
+       mutex_unlock(&tty->output_lock);
+
+       if (tty->ops->flush_chars)
+               tty->ops->flush_chars(tty);
+}
+
+/**
+ *     add_echo_byte   -       add a byte to the echo buffer
+ *     @c: unicode byte to echo
+ *     @tty: terminal device
+ *
+ *     Add a character or operation byte to the echo buffer.
+ *
+ *     Should be called under the echo lock to protect the echo buffer.
+ */
+
+static void add_echo_byte(unsigned char c, struct tty_struct *tty)
+{
+       int     new_byte_pos;
+
+       if (tty->echo_cnt == N_TTY_BUF_SIZE) {
+               /* Circular buffer is already at capacity */
+               new_byte_pos = tty->echo_pos;
+
+               /*
+                * Since the buffer start position needs to be advanced,
+                * be sure to step by a whole operation byte group.
+                */
+               if (tty->echo_buf[tty->echo_pos] == ECHO_OP_START) {
+                       if (tty->echo_buf[(tty->echo_pos + 1) &
+                                         (N_TTY_BUF_SIZE - 1)] ==
+                                               ECHO_OP_ERASE_TAB) {
+                               tty->echo_pos += 3;
+                               tty->echo_cnt -= 2;
+                       } else {
+                               tty->echo_pos += 2;
+                               tty->echo_cnt -= 1;
+                       }
+               } else {
+                       tty->echo_pos++;
+               }
+               tty->echo_pos &= N_TTY_BUF_SIZE - 1;
+
+               tty->echo_overrun = 1;
+       } else {
+               new_byte_pos = tty->echo_pos + tty->echo_cnt;
+               new_byte_pos &= N_TTY_BUF_SIZE - 1;
+               tty->echo_cnt++;
+       }
+
+       tty->echo_buf[new_byte_pos] = c;
+}
+
+/**
+ *     echo_move_back_col      -       add operation to move back a column
+ *     @tty: terminal device
+ *
+ *     Add an operation to the echo buffer to move back one column.
+ *
+ *     Locking: echo_lock to protect the echo buffer
+ */
+
+static void echo_move_back_col(struct tty_struct *tty)
+{
+       mutex_lock(&tty->echo_lock);
+
+       add_echo_byte(ECHO_OP_START, tty);
+       add_echo_byte(ECHO_OP_MOVE_BACK_COL, tty);
+
+       mutex_unlock(&tty->echo_lock);
+}
+
+/**
+ *     echo_set_canon_col      -       add operation to set the canon column
+ *     @tty: terminal device
+ *
+ *     Add an operation to the echo buffer to set the canon column
+ *     to the current column.
+ *
+ *     Locking: echo_lock to protect the echo buffer
+ */
+
+static void echo_set_canon_col(struct tty_struct *tty)
+{
+       mutex_lock(&tty->echo_lock);
+
+       add_echo_byte(ECHO_OP_START, tty);
+       add_echo_byte(ECHO_OP_SET_CANON_COL, tty);
+
+       mutex_unlock(&tty->echo_lock);
+}
+
+/**
+ *     echo_erase_tab  -       add operation to erase a tab
+ *     @num_chars: number of character columns already used
+ *     @after_tab: true if num_chars starts after a previous tab
+ *     @tty: terminal device
+ *
+ *     Add an operation to the echo buffer to erase a tab.
+ *
+ *     Called by the eraser function, which knows how many character
+ *     columns have been used since either a previous tab or the start
+ *     of input.  This information will be used later, along with
+ *     canon column (if applicable), to go back the correct number
+ *     of columns.
+ *
+ *     Locking: echo_lock to protect the echo buffer
+ */
+
+static void echo_erase_tab(unsigned int num_chars, int after_tab,
+                          struct tty_struct *tty)
+{
+       mutex_lock(&tty->echo_lock);
+
+       add_echo_byte(ECHO_OP_START, tty);
+       add_echo_byte(ECHO_OP_ERASE_TAB, tty);
+
+       /* We only need to know this modulo 8 (tab spacing) */
+       num_chars &= 7;
+
+       /* Set the high bit as a flag if num_chars is after a previous tab */
+       if (after_tab)
+               num_chars |= 0x80;
+
+       add_echo_byte(num_chars, tty);
+
+       mutex_unlock(&tty->echo_lock);
+}
+
+/**
+ *     echo_char_raw   -       echo a character raw
+ *     @c: unicode byte to echo
+ *     @tty: terminal device
+ *
+ *     Echo user input back onto the screen. This must be called only when
+ *     L_ECHO(tty) is true. Called from the driver receive_buf path.
+ *
+ *     This variant does not treat control characters specially.
+ *
+ *     Locking: echo_lock to protect the echo buffer
+ */
+
+static void echo_char_raw(unsigned char c, struct tty_struct *tty)
+{
+       mutex_lock(&tty->echo_lock);
+
+       if (c == ECHO_OP_START) {
+               add_echo_byte(ECHO_OP_START, tty);
+               add_echo_byte(ECHO_OP_START, tty);
+       } else {
+               add_echo_byte(c, tty);
+       }
+
+       mutex_unlock(&tty->echo_lock);
+}
+
+/**
+ *     echo_char       -       echo a character
+ *     @c: unicode byte to echo
+ *     @tty: terminal device
+ *
+ *     Echo user input back onto the screen. This must be called only when
+ *     L_ECHO(tty) is true. Called from the driver receive_buf path.
+ *
+ *     This variant tags control characters to be echoed as "^X"
+ *     (where X is the letter representing the control char).
+ *
+ *     Locking: echo_lock to protect the echo buffer
+ */
+
+static void echo_char(unsigned char c, struct tty_struct *tty)
+{
+       mutex_lock(&tty->echo_lock);
+
+       if (c == ECHO_OP_START) {
+               add_echo_byte(ECHO_OP_START, tty);
+               add_echo_byte(ECHO_OP_START, tty);
+       } else {
+               if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t')
+                       add_echo_byte(ECHO_OP_START, tty);
+               add_echo_byte(c, tty);
+       }
+
+       mutex_unlock(&tty->echo_lock);
+}
+
+/**
+ *     finish_erasing          -       complete erase
+ *     @tty: tty doing the erase
+ */
+
+static inline void finish_erasing(struct tty_struct *tty)
+{
+       if (tty->erasing) {
+               echo_char_raw('/', tty);
+               tty->erasing = 0;
+       }
+}
+
+/**
+ *     eraser          -       handle erase function
+ *     @c: character input
+ *     @tty: terminal device
+ *
+ *     Perform erase and necessary output when an erase character is
+ *     present in the stream from the driver layer. Handles the complexities
+ *     of UTF-8 multibyte symbols.
+ *
+ *     Locking: read_lock for tty buffers
+ */
+
+static void eraser(unsigned char c, struct tty_struct *tty)
+{
+       enum { ERASE, WERASE, KILL } kill_type;
+       int head, seen_alnums, cnt;
+       unsigned long flags;
+
+       /* FIXME: locking needed ? */
+       if (tty->read_head == tty->canon_head) {
+               /* process_output('\a', tty); */ /* what do you think? */
+               return;
+       }
+       if (c == ERASE_CHAR(tty))
+               kill_type = ERASE;
+       else if (c == WERASE_CHAR(tty))
+               kill_type = WERASE;
+       else {
+               if (!L_ECHO(tty)) {
+                       spin_lock_irqsave(&tty->read_lock, flags);
+                       tty->read_cnt -= ((tty->read_head - tty->canon_head) &
+                                         (N_TTY_BUF_SIZE - 1));
+                       tty->read_head = tty->canon_head;
+                       spin_unlock_irqrestore(&tty->read_lock, flags);
+                       return;
+               }
+               if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
+                       spin_lock_irqsave(&tty->read_lock, flags);
+                       tty->read_cnt -= ((tty->read_head - tty->canon_head) &
+                                         (N_TTY_BUF_SIZE - 1));
+                       tty->read_head = tty->canon_head;
+                       spin_unlock_irqrestore(&tty->read_lock, flags);
+                       finish_erasing(tty);
+                       echo_char(KILL_CHAR(tty), tty);
+                       /* Add a newline if ECHOK is on and ECHOKE is off. */
+                       if (L_ECHOK(tty))
+                               echo_char_raw('\n', tty);
+                       return;
+               }
+               kill_type = KILL;
+       }
+
+       seen_alnums = 0;
+       /* FIXME: Locking ?? */
+       while (tty->read_head != tty->canon_head) {
+               head = tty->read_head;
+
+               /* erase a single possibly multibyte character */
+               do {
+                       head = (head - 1) & (N_TTY_BUF_SIZE-1);
+                       c = tty->read_buf[head];
+               } while (is_continuation(c, tty) && head != tty->canon_head);
+
+               /* do not partially erase */
+               if (is_continuation(c, tty))
+                       break;
+
+               if (kill_type == WERASE) {
+                       /* Equivalent to BSD's ALTWERASE. */
+                       if (isalnum(c) || c == '_')
+                               seen_alnums++;
+                       else if (seen_alnums)
+                               break;
+               }
+               cnt = (tty->read_head - head) & (N_TTY_BUF_SIZE-1);
+               spin_lock_irqsave(&tty->read_lock, flags);
+               tty->read_head = head;
+               tty->read_cnt -= cnt;
+               spin_unlock_irqrestore(&tty->read_lock, flags);
+               if (L_ECHO(tty)) {
+                       if (L_ECHOPRT(tty)) {
+                               if (!tty->erasing) {
+                                       echo_char_raw('\\', tty);
+                                       tty->erasing = 1;
+                               }
+                               /* if cnt > 1, output a multi-byte character */
+                               echo_char(c, tty);
+                               while (--cnt > 0) {
+                                       head = (head+1) & (N_TTY_BUF_SIZE-1);
+                                       echo_char_raw(tty->read_buf[head], tty);
+                                       echo_move_back_col(tty);
+                               }
+                       } else if (kill_type == ERASE && !L_ECHOE(tty)) {
+                               echo_char(ERASE_CHAR(tty), tty);
+                       } else if (c == '\t') {
+                               unsigned int num_chars = 0;
+                               int after_tab = 0;
+                               unsigned long tail = tty->read_head;
+
+                               /*
+                                * Count the columns used for characters
+                                * since the start of input or after a
+                                * previous tab.
+                                * This info is used to go back the correct
+                                * number of columns.
+                                */
+                               while (tail != tty->canon_head) {
+                                       tail = (tail-1) & (N_TTY_BUF_SIZE-1);
+                                       c = tty->read_buf[tail];
+                                       if (c == '\t') {
+                                               after_tab = 1;
+                                               break;
+                                       } else if (iscntrl(c)) {
+                                               if (L_ECHOCTL(tty))
+                                                       num_chars += 2;
+                                       } else if (!is_continuation(c, tty)) {
+                                               num_chars++;
+                                       }
+                               }
+                               echo_erase_tab(num_chars, after_tab, tty);
+                       } else {
+                               if (iscntrl(c) && L_ECHOCTL(tty)) {
+                                       echo_char_raw('\b', tty);
+                                       echo_char_raw(' ', tty);
+                                       echo_char_raw('\b', tty);
+                               }
+                               if (!iscntrl(c) || L_ECHOCTL(tty)) {
+                                       echo_char_raw('\b', tty);
+                                       echo_char_raw(' ', tty);
+                                       echo_char_raw('\b', tty);
+                               }
+                       }
+               }
+               if (kill_type == ERASE)
+                       break;
+       }
+       if (tty->read_head == tty->canon_head && L_ECHO(tty))
+               finish_erasing(tty);
+}
+
+/**
+ *     isig            -       handle the ISIG optio
+ *     @sig: signal
+ *     @tty: terminal
+ *     @flush: force flush
+ *
+ *     Called when a signal is being sent due to terminal input. This
+ *     may caus terminal flushing to take place according to the termios
+ *     settings and character used. Called from the driver receive_buf
+ *     path so serialized.
+ *
+ *     Locking: ctrl_lock, read_lock (both via flush buffer)
+ */
+
+static inline void isig(int sig, struct tty_struct *tty, int flush)
+{
+       if (tty->pgrp)
+               kill_pgrp(tty->pgrp, sig, 1);
+       if (flush || !L_NOFLSH(tty)) {
+               n_tty_flush_buffer(tty);
+               tty_driver_flush_buffer(tty);
+       }
+}
+
+/**
+ *     n_tty_receive_break     -       handle break
+ *     @tty: terminal
+ *
+ *     An RS232 break event has been hit in the incoming bitstream. This
+ *     can cause a variety of events depending upon the termios settings.
+ *
+ *     Called from the receive_buf path so single threaded.
+ */
+
+static inline void n_tty_receive_break(struct tty_struct *tty)
+{
+       if (I_IGNBRK(tty))
+               return;
+       if (I_BRKINT(tty)) {
+               isig(SIGINT, tty, 1);
+               return;
+       }
+       if (I_PARMRK(tty)) {
+               put_tty_queue('\377', tty);
+               put_tty_queue('\0', tty);
+       }
+       put_tty_queue('\0', tty);
+       wake_up_interruptible(&tty->read_wait);
+}
+
+/**
+ *     n_tty_receive_overrun   -       handle overrun reporting
+ *     @tty: terminal
+ *
+ *     Data arrived faster than we could process it. While the tty
+ *     driver has flagged this the bits that were missed are gone
+ *     forever.
+ *
+ *     Called from the receive_buf path so single threaded. Does not
+ *     need locking as num_overrun and overrun_time are function
+ *     private.
+ */
+
+static inline void n_tty_receive_overrun(struct tty_struct *tty)
+{
+       char buf[64];
+
+       tty->num_overrun++;
+       if (time_before(tty->overrun_time, jiffies - HZ) ||
+                       time_after(tty->overrun_time, jiffies)) {
+               printk(KERN_WARNING "%s: %d input overrun(s)\n",
+                       tty_name(tty, buf),
+                       tty->num_overrun);
+               tty->overrun_time = jiffies;
+               tty->num_overrun = 0;
+       }
+}
+
+/**
+ *     n_tty_receive_parity_error      -       error notifier
+ *     @tty: terminal device
+ *     @c: character
+ *
+ *     Process a parity error and queue the right data to indicate
+ *     the error case if necessary. Locking as per n_tty_receive_buf.
+ */
+static inline void n_tty_receive_parity_error(struct tty_struct *tty,
+                                             unsigned char c)
+{
+       if (I_IGNPAR(tty))
+               return;
+       if (I_PARMRK(tty)) {
+               put_tty_queue('\377', tty);
+               put_tty_queue('\0', tty);
+               put_tty_queue(c, tty);
+       } else  if (I_INPCK(tty))
+               put_tty_queue('\0', tty);
+       else
+               put_tty_queue(c, tty);
+       wake_up_interruptible(&tty->read_wait);
+}
+
+/**
+ *     n_tty_receive_char      -       perform processing
+ *     @tty: terminal device
+ *     @c: character
+ *
+ *     Process an individual character of input received from the driver.
+ *     This is serialized with respect to itself by the rules for the
+ *     driver above.
+ */
+
+static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
+{
+       unsigned long flags;
+       int parmrk;
+
+       if (tty->raw) {
+               put_tty_queue(c, tty);
+               return;
+       }
+
+       if (I_ISTRIP(tty))
+               c &= 0x7f;
+       if (I_IUCLC(tty) && L_IEXTEN(tty))
+               c = tolower(c);
+
+       if (L_EXTPROC(tty)) {
+               put_tty_queue(c, tty);
+               return;
+       }
+
+       if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
+           I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty) &&
+           c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty)) {
+               start_tty(tty);
+               process_echoes(tty);
+       }
+
+       if (tty->closing) {
+               if (I_IXON(tty)) {
+                       if (c == START_CHAR(tty)) {
+                               start_tty(tty);
+                               process_echoes(tty);
+                       } else if (c == STOP_CHAR(tty))
+                               stop_tty(tty);
+               }
+               return;
+       }
+
+       /*
+        * If the previous character was LNEXT, or we know that this
+        * character is not one of the characters that we'll have to
+        * handle specially, do shortcut processing to speed things
+        * up.
+        */
+       if (!test_bit(c, tty->process_char_map) || tty->lnext) {
+               tty->lnext = 0;
+               parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
+               if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
+                       /* beep if no space */
+                       if (L_ECHO(tty))
+                               process_output('\a', tty);
+                       return;
+               }
+               if (L_ECHO(tty)) {
+                       finish_erasing(tty);
+                       /* Record the column of first canon char. */
+                       if (tty->canon_head == tty->read_head)
+                               echo_set_canon_col(tty);
+                       echo_char(c, tty);
+                       process_echoes(tty);
+               }
+               if (parmrk)
+                       put_tty_queue(c, tty);
+               put_tty_queue(c, tty);
+               return;
+       }
+
+       if (I_IXON(tty)) {
+               if (c == START_CHAR(tty)) {
+                       start_tty(tty);
+                       process_echoes(tty);
+                       return;
+               }
+               if (c == STOP_CHAR(tty)) {
+                       stop_tty(tty);
+                       return;
+               }
+       }
+
+       if (L_ISIG(tty)) {
+               int signal;
+               signal = SIGINT;
+               if (c == INTR_CHAR(tty))
+                       goto send_signal;
+               signal = SIGQUIT;
+               if (c == QUIT_CHAR(tty))
+                       goto send_signal;
+               signal = SIGTSTP;
+               if (c == SUSP_CHAR(tty)) {
+send_signal:
+                       /*
+                        * Note that we do not use isig() here because we want
+                        * the order to be:
+                        * 1) flush, 2) echo, 3) signal
+                        */
+                       if (!L_NOFLSH(tty)) {
+                               n_tty_flush_buffer(tty);
+                               tty_driver_flush_buffer(tty);
+                       }
+                       if (I_IXON(tty))
+                               start_tty(tty);
+                       if (L_ECHO(tty)) {
+                               echo_char(c, tty);
+                               process_echoes(tty);
+                       }
+                       if (tty->pgrp)
+                               kill_pgrp(tty->pgrp, signal, 1);
+                       return;
+               }
+       }
+
+       if (c == '\r') {
+               if (I_IGNCR(tty))
+                       return;
+               if (I_ICRNL(tty))
+                       c = '\n';
+       } else if (c == '\n' && I_INLCR(tty))
+               c = '\r';
+
+       if (tty->icanon) {
+               if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
+                   (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
+                       eraser(c, tty);
+                       process_echoes(tty);
+                       return;
+               }
+               if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
+                       tty->lnext = 1;
+                       if (L_ECHO(tty)) {
+                               finish_erasing(tty);
+                               if (L_ECHOCTL(tty)) {
+                                       echo_char_raw('^', tty);
+                                       echo_char_raw('\b', tty);
+                                       process_echoes(tty);
+                               }
+                       }
+                       return;
+               }
+               if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
+                   L_IEXTEN(tty)) {
+                       unsigned long tail = tty->canon_head;
+
+                       finish_erasing(tty);
+                       echo_char(c, tty);
+                       echo_char_raw('\n', tty);
+                       while (tail != tty->read_head) {
+                               echo_char(tty->read_buf[tail], tty);
+                               tail = (tail+1) & (N_TTY_BUF_SIZE-1);
+                       }
+                       process_echoes(tty);
+                       return;
+               }
+               if (c == '\n') {
+                       if (tty->read_cnt >= N_TTY_BUF_SIZE) {
+                               if (L_ECHO(tty))
+                                       process_output('\a', tty);
+                               return;
+                       }
+                       if (L_ECHO(tty) || L_ECHONL(tty)) {
+                               echo_char_raw('\n', tty);
+                               process_echoes(tty);
+                       }
+                       goto handle_newline;
+               }
+               if (c == EOF_CHAR(tty)) {
+                       if (tty->read_cnt >= N_TTY_BUF_SIZE)
+                               return;
+                       if (tty->canon_head != tty->read_head)
+                               set_bit(TTY_PUSH, &tty->flags);
+                       c = __DISABLED_CHAR;
+                       goto handle_newline;
+               }
+               if ((c == EOL_CHAR(tty)) ||
+                   (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
+                       parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
+                                ? 1 : 0;
+                       if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
+                               if (L_ECHO(tty))
+                                       process_output('\a', tty);
+                               return;
+                       }
+                       /*
+                        * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
+                        */
+                       if (L_ECHO(tty)) {
+                               /* Record the column of first canon char. */
+                               if (tty->canon_head == tty->read_head)
+                                       echo_set_canon_col(tty);
+                               echo_char(c, tty);
+                               process_echoes(tty);
+                       }
+                       /*
+                        * XXX does PARMRK doubling happen for
+                        * EOL_CHAR and EOL2_CHAR?
+                        */
+                       if (parmrk)
+                               put_tty_queue(c, tty);
+
+handle_newline:
+                       spin_lock_irqsave(&tty->read_lock, flags);
+                       set_bit(tty->read_head, tty->read_flags);
+                       put_tty_queue_nolock(c, tty);
+                       tty->canon_head = tty->read_head;
+                       tty->canon_data++;
+                       spin_unlock_irqrestore(&tty->read_lock, flags);
+                       kill_fasync(&tty->fasync, SIGIO, POLL_IN);
+                       if (waitqueue_active(&tty->read_wait))
+                               wake_up_interruptible(&tty->read_wait);
+                       return;
+               }
+       }
+
+       parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
+       if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
+               /* beep if no space */
+               if (L_ECHO(tty))
+                       process_output('\a', tty);
+               return;
+       }
+       if (L_ECHO(tty)) {
+               finish_erasing(tty);
+               if (c == '\n')
+                       echo_char_raw('\n', tty);
+               else {
+                       /* Record the column of first canon char. */
+                       if (tty->canon_head == tty->read_head)
+                               echo_set_canon_col(tty);
+                       echo_char(c, tty);
+               }
+               process_echoes(tty);
+       }
+
+       if (parmrk)
+               put_tty_queue(c, tty);
+
+       put_tty_queue(c, tty);
+}
+
+
+/**
+ *     n_tty_write_wakeup      -       asynchronous I/O notifier
+ *     @tty: tty device
+ *
+ *     Required for the ptys, serial driver etc. since processes
+ *     that attach themselves to the master and rely on ASYNC
+ *     IO must be woken up
+ */
+
+static void n_tty_write_wakeup(struct tty_struct *tty)
+{
+       if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags))
+               kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
+}
+
+/**
+ *     n_tty_receive_buf       -       data receive
+ *     @tty: terminal device
+ *     @cp: buffer
+ *     @fp: flag buffer
+ *     @count: characters
+ *
+ *     Called by the terminal driver when a block of characters has
+ *     been received. This function must be called from soft contexts
+ *     not from interrupt context. The driver is responsible for making
+ *     calls one at a time and in order (or using flush_to_ldisc)
+ */
+
+static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                             char *fp, int count)
+{
+       const unsigned char *p;
+       char *f, flags = TTY_NORMAL;
+       int     i;
+       char    buf[64];
+       unsigned long cpuflags;
+
+       if (!tty->read_buf)
+               return;
+
+       if (tty->real_raw) {
+               spin_lock_irqsave(&tty->read_lock, cpuflags);
+               i = min(N_TTY_BUF_SIZE - tty->read_cnt,
+                       N_TTY_BUF_SIZE - tty->read_head);
+               i = min(count, i);
+               memcpy(tty->read_buf + tty->read_head, cp, i);
+               tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
+               tty->read_cnt += i;
+               cp += i;
+               count -= i;
+
+               i = min(N_TTY_BUF_SIZE - tty->read_cnt,
+                       N_TTY_BUF_SIZE - tty->read_head);
+               i = min(count, i);
+               memcpy(tty->read_buf + tty->read_head, cp, i);
+               tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
+               tty->read_cnt += i;
+               spin_unlock_irqrestore(&tty->read_lock, cpuflags);
+       } else {
+               for (i = count, p = cp, f = fp; i; i--, p++) {
+                       if (f)
+                               flags = *f++;
+                       switch (flags) {
+                       case TTY_NORMAL:
+                               n_tty_receive_char(tty, *p);
+                               break;
+                       case TTY_BREAK:
+                               n_tty_receive_break(tty);
+                               break;
+                       case TTY_PARITY:
+                       case TTY_FRAME:
+                               n_tty_receive_parity_error(tty, *p);
+                               break;
+                       case TTY_OVERRUN:
+                               n_tty_receive_overrun(tty);
+                               break;
+                       default:
+                               printk(KERN_ERR "%s: unknown flag %d\n",
+                                      tty_name(tty, buf), flags);
+                               break;
+                       }
+               }
+               if (tty->ops->flush_chars)
+                       tty->ops->flush_chars(tty);
+       }
+
+       n_tty_set_room(tty);
+
+       if ((!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) ||
+               L_EXTPROC(tty)) {
+               kill_fasync(&tty->fasync, SIGIO, POLL_IN);
+               if (waitqueue_active(&tty->read_wait))
+                       wake_up_interruptible(&tty->read_wait);
+       }
+
+       /*
+        * Check the remaining room for the input canonicalization
+        * mode.  We don't want to throttle the driver if we're in
+        * canonical mode and don't have a newline yet!
+        */
+       if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
+               tty_throttle(tty);
+}
+
+int is_ignored(int sig)
+{
+       return (sigismember(&current->blocked, sig) ||
+               current->sighand->action[sig-1].sa.sa_handler == SIG_IGN);
+}
+
+/**
+ *     n_tty_set_termios       -       termios data changed
+ *     @tty: terminal
+ *     @old: previous data
+ *
+ *     Called by the tty layer when the user changes termios flags so
+ *     that the line discipline can plan ahead. This function cannot sleep
+ *     and is protected from re-entry by the tty layer. The user is
+ *     guaranteed that this function will not be re-entered or in progress
+ *     when the ldisc is closed.
+ *
+ *     Locking: Caller holds tty->termios_mutex
+ */
+
+static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
+{
+       int canon_change = 1;
+       BUG_ON(!tty);
+
+       if (old)
+               canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON;
+       if (canon_change) {
+               memset(&tty->read_flags, 0, sizeof tty->read_flags);
+               tty->canon_head = tty->read_tail;
+               tty->canon_data = 0;
+               tty->erasing = 0;
+       }
+
+       if (canon_change && !L_ICANON(tty) && tty->read_cnt)
+               wake_up_interruptible(&tty->read_wait);
+
+       tty->icanon = (L_ICANON(tty) != 0);
+       if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
+               tty->raw = 1;
+               tty->real_raw = 1;
+               n_tty_set_room(tty);
+               return;
+       }
+       if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
+           I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
+           I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
+           I_PARMRK(tty)) {
+               memset(tty->process_char_map, 0, 256/8);
+
+               if (I_IGNCR(tty) || I_ICRNL(tty))
+                       set_bit('\r', tty->process_char_map);
+               if (I_INLCR(tty))
+                       set_bit('\n', tty->process_char_map);
+
+               if (L_ICANON(tty)) {
+                       set_bit(ERASE_CHAR(tty), tty->process_char_map);
+                       set_bit(KILL_CHAR(tty), tty->process_char_map);
+                       set_bit(EOF_CHAR(tty), tty->process_char_map);
+                       set_bit('\n', tty->process_char_map);
+                       set_bit(EOL_CHAR(tty), tty->process_char_map);
+                       if (L_IEXTEN(tty)) {
+                               set_bit(WERASE_CHAR(tty),
+                                       tty->process_char_map);
+                               set_bit(LNEXT_CHAR(tty),
+                                       tty->process_char_map);
+                               set_bit(EOL2_CHAR(tty),
+                                       tty->process_char_map);
+                               if (L_ECHO(tty))
+                                       set_bit(REPRINT_CHAR(tty),
+                                               tty->process_char_map);
+                       }
+               }
+               if (I_IXON(tty)) {
+                       set_bit(START_CHAR(tty), tty->process_char_map);
+                       set_bit(STOP_CHAR(tty), tty->process_char_map);
+               }
+               if (L_ISIG(tty)) {
+                       set_bit(INTR_CHAR(tty), tty->process_char_map);
+                       set_bit(QUIT_CHAR(tty), tty->process_char_map);
+                       set_bit(SUSP_CHAR(tty), tty->process_char_map);
+               }
+               clear_bit(__DISABLED_CHAR, tty->process_char_map);
+               tty->raw = 0;
+               tty->real_raw = 0;
+       } else {
+               tty->raw = 1;
+               if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&
+                   (I_IGNPAR(tty) || !I_INPCK(tty)) &&
+                   (tty->driver->flags & TTY_DRIVER_REAL_RAW))
+                       tty->real_raw = 1;
+               else
+                       tty->real_raw = 0;
+       }
+       n_tty_set_room(tty);
+       /* The termios change make the tty ready for I/O */
+       wake_up_interruptible(&tty->write_wait);
+       wake_up_interruptible(&tty->read_wait);
+}
+
+/**
+ *     n_tty_close             -       close the ldisc for this tty
+ *     @tty: device
+ *
+ *     Called from the terminal layer when this line discipline is
+ *     being shut down, either because of a close or becsuse of a
+ *     discipline change. The function will not be called while other
+ *     ldisc methods are in progress.
+ */
+
+static void n_tty_close(struct tty_struct *tty)
+{
+       n_tty_flush_buffer(tty);
+       if (tty->read_buf) {
+               kfree(tty->read_buf);
+               tty->read_buf = NULL;
+       }
+       if (tty->echo_buf) {
+               kfree(tty->echo_buf);
+               tty->echo_buf = NULL;
+       }
+}
+
+/**
+ *     n_tty_open              -       open an ldisc
+ *     @tty: terminal to open
+ *
+ *     Called when this line discipline is being attached to the
+ *     terminal device. Can sleep. Called serialized so that no
+ *     other events will occur in parallel. No further open will occur
+ *     until a close.
+ */
+
+static int n_tty_open(struct tty_struct *tty)
+{
+       if (!tty)
+               return -EINVAL;
+
+       /* These are ugly. Currently a malloc failure here can panic */
+       if (!tty->read_buf) {
+               tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+               if (!tty->read_buf)
+                       return -ENOMEM;
+       }
+       if (!tty->echo_buf) {
+               tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+
+               if (!tty->echo_buf)
+                       return -ENOMEM;
+       }
+       reset_buffer_flags(tty);
+       tty->column = 0;
+       n_tty_set_termios(tty, NULL);
+       tty->minimum_to_wake = 1;
+       tty->closing = 0;
+       return 0;
+}
+
+static inline int input_available_p(struct tty_struct *tty, int amt)
+{
+       tty_flush_to_ldisc(tty);
+       if (tty->icanon && !L_EXTPROC(tty)) {
+               if (tty->canon_data)
+                       return 1;
+       } else if (tty->read_cnt >= (amt ? amt : 1))
+               return 1;
+
+       return 0;
+}
+
+/**
+ *     copy_from_read_buf      -       copy read data directly
+ *     @tty: terminal device
+ *     @b: user data
+ *     @nr: size of data
+ *
+ *     Helper function to speed up n_tty_read.  It is only called when
+ *     ICANON is off; it copies characters straight from the tty queue to
+ *     user space directly.  It can be profitably called twice; once to
+ *     drain the space from the tail pointer to the (physical) end of the
+ *     buffer, and once to drain the space from the (physical) beginning of
+ *     the buffer to head pointer.
+ *
+ *     Called under the tty->atomic_read_lock sem
+ *
+ */
+
+static int copy_from_read_buf(struct tty_struct *tty,
+                                     unsigned char __user **b,
+                                     size_t *nr)
+
+{
+       int retval;
+       size_t n;
+       unsigned long flags;
+
+       retval = 0;
+       spin_lock_irqsave(&tty->read_lock, flags);
+       n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail);
+       n = min(*nr, n);
+       spin_unlock_irqrestore(&tty->read_lock, flags);
+       if (n) {
+               retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
+               n -= retval;
+               tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
+               spin_lock_irqsave(&tty->read_lock, flags);
+               tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
+               tty->read_cnt -= n;
+               /* Turn single EOF into zero-length read */
+               if (L_EXTPROC(tty) && tty->icanon && n == 1) {
+                       if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
+                               n--;
+               }
+               spin_unlock_irqrestore(&tty->read_lock, flags);
+               *b += n;
+               *nr -= n;
+       }
+       return retval;
+}
+
+extern ssize_t redirected_tty_write(struct file *, const char __user *,
+                                                       size_t, loff_t *);
+
+/**
+ *     job_control             -       check job control
+ *     @tty: tty
+ *     @file: file handle
+ *
+ *     Perform job control management checks on this file/tty descriptor
+ *     and if appropriate send any needed signals and return a negative
+ *     error code if action should be taken.
+ *
+ *     FIXME:
+ *     Locking: None - redirected write test is safe, testing
+ *     current->signal should possibly lock current->sighand
+ *     pgrp locking ?
+ */
+
+static int job_control(struct tty_struct *tty, struct file *file)
+{
+       /* Job control check -- must be done at start and after
+          every sleep (POSIX.1 7.1.1.4). */
+       /* NOTE: not yet done after every sleep pending a thorough
+          check of the logic of this change. -- jlc */
+       /* don't stop on /dev/console */
+       if (file->f_op->write != redirected_tty_write &&
+           current->signal->tty == tty) {
+               if (!tty->pgrp)
+                       printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
+               else if (task_pgrp(current) != tty->pgrp) {
+                       if (is_ignored(SIGTTIN) ||
+                           is_current_pgrp_orphaned())
+                               return -EIO;
+                       kill_pgrp(task_pgrp(current), SIGTTIN, 1);
+                       set_thread_flag(TIF_SIGPENDING);
+                       return -ERESTARTSYS;
+               }
+       }
+       return 0;
+}
+
+
+/**
+ *     n_tty_read              -       read function for tty
+ *     @tty: tty device
+ *     @file: file object
+ *     @buf: userspace buffer pointer
+ *     @nr: size of I/O
+ *
+ *     Perform reads for the line discipline. We are guaranteed that the
+ *     line discipline will not be closed under us but we may get multiple
+ *     parallel readers and must handle this ourselves. We may also get
+ *     a hangup. Always called in user context, may sleep.
+ *
+ *     This code must be sure never to sleep through a hangup.
+ */
+
+static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
+                        unsigned char __user *buf, size_t nr)
+{
+       unsigned char __user *b = buf;
+       DECLARE_WAITQUEUE(wait, current);
+       int c;
+       int minimum, time;
+       ssize_t retval = 0;
+       ssize_t size;
+       long timeout;
+       unsigned long flags;
+       int packet;
+
+do_it_again:
+
+       BUG_ON(!tty->read_buf);
+
+       c = job_control(tty, file);
+       if (c < 0)
+               return c;
+
+       minimum = time = 0;
+       timeout = MAX_SCHEDULE_TIMEOUT;
+       if (!tty->icanon) {
+               time = (HZ / 10) * TIME_CHAR(tty);
+               minimum = MIN_CHAR(tty);
+               if (minimum) {
+                       if (time)
+                               tty->minimum_to_wake = 1;
+                       else if (!waitqueue_active(&tty->read_wait) ||
+                                (tty->minimum_to_wake > minimum))
+                               tty->minimum_to_wake = minimum;
+               } else {
+                       timeout = 0;
+                       if (time) {
+                               timeout = time;
+                               time = 0;
+                       }
+                       tty->minimum_to_wake = minimum = 1;
+               }
+       }
+
+       /*
+        *      Internal serialization of reads.
+        */
+       if (file->f_flags & O_NONBLOCK) {
+               if (!mutex_trylock(&tty->atomic_read_lock))
+                       return -EAGAIN;
+       } else {
+               if (mutex_lock_interruptible(&tty->atomic_read_lock))
+                       return -ERESTARTSYS;
+       }
+       packet = tty->packet;
+
+       add_wait_queue(&tty->read_wait, &wait);
+       while (nr) {
+               /* First test for status change. */
+               if (packet && tty->link->ctrl_status) {
+                       unsigned char cs;
+                       if (b != buf)
+                               break;
+                       spin_lock_irqsave(&tty->link->ctrl_lock, flags);
+                       cs = tty->link->ctrl_status;
+                       tty->link->ctrl_status = 0;
+                       spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
+                       if (tty_put_user(tty, cs, b++)) {
+                               retval = -EFAULT;
+                               b--;
+                               break;
+                       }
+                       nr--;
+                       break;
+               }
+               /* This statement must be first before checking for input
+                  so that any interrupt will set the state back to
+                  TASK_RUNNING. */
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               if (((minimum - (b - buf)) < tty->minimum_to_wake) &&
+                   ((minimum - (b - buf)) >= 1))
+                       tty->minimum_to_wake = (minimum - (b - buf));
+
+               if (!input_available_p(tty, 0)) {
+                       if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
+                               retval = -EIO;
+                               break;
+                       }
+                       if (tty_hung_up_p(file))
+                               break;
+                       if (!timeout)
+                               break;
+                       if (file->f_flags & O_NONBLOCK) {
+                               retval = -EAGAIN;
+                               break;
+                       }
+                       if (signal_pending(current)) {
+                               retval = -ERESTARTSYS;
+                               break;
+                       }
+                       /* FIXME: does n_tty_set_room need locking ? */
+                       n_tty_set_room(tty);
+                       timeout = schedule_timeout(timeout);
+                       continue;
+               }
+               __set_current_state(TASK_RUNNING);
+
+               /* Deal with packet mode. */
+               if (packet && b == buf) {
+                       if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
+                               retval = -EFAULT;
+                               b--;
+                               break;
+                       }
+                       nr--;
+               }
+
+               if (tty->icanon && !L_EXTPROC(tty)) {
+                       /* N.B. avoid overrun if nr == 0 */
+                       while (nr && tty->read_cnt) {
+                               int eol;
+
+                               eol = test_and_clear_bit(tty->read_tail,
+                                               tty->read_flags);
+                               c = tty->read_buf[tty->read_tail];
+                               spin_lock_irqsave(&tty->read_lock, flags);
+                               tty->read_tail = ((tty->read_tail+1) &
+                                                 (N_TTY_BUF_SIZE-1));
+                               tty->read_cnt--;
+                               if (eol) {
+                                       /* this test should be redundant:
+                                        * we shouldn't be reading data if
+                                        * canon_data is 0
+                                        */
+                                       if (--tty->canon_data < 0)
+                                               tty->canon_data = 0;
+                               }
+                               spin_unlock_irqrestore(&tty->read_lock, flags);
+
+                               if (!eol || (c != __DISABLED_CHAR)) {
+                                       if (tty_put_user(tty, c, b++)) {
+                                               retval = -EFAULT;
+                                               b--;
+                                               break;
+                                       }
+                                       nr--;
+                               }
+                               if (eol) {
+                                       tty_audit_push(tty);
+                                       break;
+                               }
+                       }
+                       if (retval)
+                               break;
+               } else {
+                       int uncopied;
+                       /* The copy function takes the read lock and handles
+                          locking internally for this case */
+                       uncopied = copy_from_read_buf(tty, &b, &nr);
+                       uncopied += copy_from_read_buf(tty, &b, &nr);
+                       if (uncopied) {
+                               retval = -EFAULT;
+                               break;
+                       }
+               }
+
+               /* If there is enough space in the read buffer now, let the
+                * low-level driver know. We use n_tty_chars_in_buffer() to
+                * check the buffer, as it now knows about canonical mode.
+                * Otherwise, if the driver is throttled and the line is
+                * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
+                * we won't get any more characters.
+                */
+               if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
+                       n_tty_set_room(tty);
+                       check_unthrottle(tty);
+               }
+
+               if (b - buf >= minimum)
+                       break;
+               if (time)
+                       timeout = time;
+       }
+       mutex_unlock(&tty->atomic_read_lock);
+       remove_wait_queue(&tty->read_wait, &wait);
+
+       if (!waitqueue_active(&tty->read_wait))
+               tty->minimum_to_wake = minimum;
+
+       __set_current_state(TASK_RUNNING);
+       size = b - buf;
+       if (size) {
+               retval = size;
+               if (nr)
+                       clear_bit(TTY_PUSH, &tty->flags);
+       } else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
+                goto do_it_again;
+
+       n_tty_set_room(tty);
+       return retval;
+}
+
+/**
+ *     n_tty_write             -       write function for tty
+ *     @tty: tty device
+ *     @file: file object
+ *     @buf: userspace buffer pointer
+ *     @nr: size of I/O
+ *
+ *     Write function of the terminal device.  This is serialized with
+ *     respect to other write callers but not to termios changes, reads
+ *     and other such events.  Since the receive code will echo characters,
+ *     thus calling driver write methods, the output_lock is used in
+ *     the output processing functions called here as well as in the
+ *     echo processing function to protect the column state and space
+ *     left in the buffer.
+ *
+ *     This code must be sure never to sleep through a hangup.
+ *
+ *     Locking: output_lock to protect column state and space left
+ *              (note that the process_output*() functions take this
+ *               lock themselves)
+ */
+
+static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
+                          const unsigned char *buf, size_t nr)
+{
+       const unsigned char *b = buf;
+       DECLARE_WAITQUEUE(wait, current);
+       int c;
+       ssize_t retval = 0;
+
+       /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
+       if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) {
+               retval = tty_check_change(tty);
+               if (retval)
+                       return retval;
+       }
+
+       /* Write out any echoed characters that are still pending */
+       process_echoes(tty);
+
+       add_wait_queue(&tty->write_wait, &wait);
+       while (1) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+               if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
+                       retval = -EIO;
+                       break;
+               }
+               if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
+                       while (nr > 0) {
+                               ssize_t num = process_output_block(tty, b, nr);
+                               if (num < 0) {
+                                       if (num == -EAGAIN)
+                                               break;
+                                       retval = num;
+                                       goto break_out;
+                               }
+                               b += num;
+                               nr -= num;
+                               if (nr == 0)
+                                       break;
+                               c = *b;
+                               if (process_output(c, tty) < 0)
+                                       break;
+                               b++; nr--;
+                       }
+                       if (tty->ops->flush_chars)
+                               tty->ops->flush_chars(tty);
+               } else {
+                       while (nr > 0) {
+                               c = tty->ops->write(tty, b, nr);
+                               if (c < 0) {
+                                       retval = c;
+                                       goto break_out;
+                               }
+                               if (!c)
+                                       break;
+                               b += c;
+                               nr -= c;
+                       }
+               }
+               if (!nr)
+                       break;
+               if (file->f_flags & O_NONBLOCK) {
+                       retval = -EAGAIN;
+                       break;
+               }
+               schedule();
+       }
+break_out:
+       __set_current_state(TASK_RUNNING);
+       remove_wait_queue(&tty->write_wait, &wait);
+       if (b - buf != nr && tty->fasync)
+               set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+       return (b - buf) ? b - buf : retval;
+}
+
+/**
+ *     n_tty_poll              -       poll method for N_TTY
+ *     @tty: terminal device
+ *     @file: file accessing it
+ *     @wait: poll table
+ *
+ *     Called when the line discipline is asked to poll() for data or
+ *     for special events. This code is not serialized with respect to
+ *     other events save open/close.
+ *
+ *     This code must be sure never to sleep through a hangup.
+ *     Called without the kernel lock held - fine
+ */
+
+static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
+                                                       poll_table *wait)
+{
+       unsigned int mask = 0;
+
+       poll_wait(file, &tty->read_wait, wait);
+       poll_wait(file, &tty->write_wait, wait);
+       if (input_available_p(tty, TIME_CHAR(tty) ? 0 : MIN_CHAR(tty)))
+               mask |= POLLIN | POLLRDNORM;
+       if (tty->packet && tty->link->ctrl_status)
+               mask |= POLLPRI | POLLIN | POLLRDNORM;
+       if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+               mask |= POLLHUP;
+       if (tty_hung_up_p(file))
+               mask |= POLLHUP;
+       if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {
+               if (MIN_CHAR(tty) && !TIME_CHAR(tty))
+                       tty->minimum_to_wake = MIN_CHAR(tty);
+               else
+                       tty->minimum_to_wake = 1;
+       }
+       if (tty->ops->write && !tty_is_writelocked(tty) &&
+                       tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
+                       tty_write_room(tty) > 0)
+               mask |= POLLOUT | POLLWRNORM;
+       return mask;
+}
+
+static unsigned long inq_canon(struct tty_struct *tty)
+{
+       int nr, head, tail;
+
+       if (!tty->canon_data)
+               return 0;
+       head = tty->canon_head;
+       tail = tty->read_tail;
+       nr = (head - tail) & (N_TTY_BUF_SIZE-1);
+       /* Skip EOF-chars.. */
+       while (head != tail) {
+               if (test_bit(tail, tty->read_flags) &&
+                   tty->read_buf[tail] == __DISABLED_CHAR)
+                       nr--;
+               tail = (tail+1) & (N_TTY_BUF_SIZE-1);
+       }
+       return nr;
+}
+
+static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       int retval;
+
+       switch (cmd) {
+       case TIOCOUTQ:
+               return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
+       case TIOCINQ:
+               /* FIXME: Locking */
+               retval = tty->read_cnt;
+               if (L_ICANON(tty))
+                       retval = inq_canon(tty);
+               return put_user(retval, (unsigned int __user *) arg);
+       default:
+               return n_tty_ioctl_helper(tty, file, cmd, arg);
+       }
+}
+
+struct tty_ldisc_ops tty_ldisc_N_TTY = {
+       .magic           = TTY_LDISC_MAGIC,
+       .name            = "n_tty",
+       .open            = n_tty_open,
+       .close           = n_tty_close,
+       .flush_buffer    = n_tty_flush_buffer,
+       .chars_in_buffer = n_tty_chars_in_buffer,
+       .read            = n_tty_read,
+       .write           = n_tty_write,
+       .ioctl           = n_tty_ioctl,
+       .set_termios     = n_tty_set_termios,
+       .poll            = n_tty_poll,
+       .receive_buf     = n_tty_receive_buf,
+       .write_wakeup    = n_tty_write_wakeup
+};
+
+/**
+ *     n_tty_inherit_ops       -       inherit N_TTY methods
+ *     @ops: struct tty_ldisc_ops where to save N_TTY methods
+ *
+ *     Used by a generic struct tty_ldisc_ops to easily inherit N_TTY
+ *     methods.
+ */
+
+void n_tty_inherit_ops(struct tty_ldisc_ops *ops)
+{
+       *ops = tty_ldisc_N_TTY;
+       ops->owner = NULL;
+       ops->refcount = ops->flags = 0;
+}
+EXPORT_SYMBOL_GPL(n_tty_inherit_ops);
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
new file mode 100644 (file)
index 0000000..923a485
--- /dev/null
@@ -0,0 +1,777 @@
+/*
+ *  linux/drivers/char/pty.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Added support for a Unix98-style ptmx device.
+ *    -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
+ *
+ *  When reading this code see also fs/devpts. In particular note that the
+ *  driver_data field is used by the devpts side as a binding to the devpts
+ *  inode.
+ */
+
+#include <linux/module.h>
+
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/major.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/sysctl.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <linux/bitops.h>
+#include <linux/devpts_fs.h>
+#include <linux/slab.h>
+
+#include <asm/system.h>
+
+#ifdef CONFIG_UNIX98_PTYS
+static struct tty_driver *ptm_driver;
+static struct tty_driver *pts_driver;
+#endif
+
+static void pty_close(struct tty_struct *tty, struct file *filp)
+{
+       BUG_ON(!tty);
+       if (tty->driver->subtype == PTY_TYPE_MASTER)
+               WARN_ON(tty->count > 1);
+       else {
+               if (tty->count > 2)
+                       return;
+       }
+       wake_up_interruptible(&tty->read_wait);
+       wake_up_interruptible(&tty->write_wait);
+       tty->packet = 0;
+       if (!tty->link)
+               return;
+       tty->link->packet = 0;
+       set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
+       wake_up_interruptible(&tty->link->read_wait);
+       wake_up_interruptible(&tty->link->write_wait);
+       if (tty->driver->subtype == PTY_TYPE_MASTER) {
+               set_bit(TTY_OTHER_CLOSED, &tty->flags);
+#ifdef CONFIG_UNIX98_PTYS
+               if (tty->driver == ptm_driver)
+                       devpts_pty_kill(tty->link);
+#endif
+               tty_unlock();
+               tty_vhangup(tty->link);
+               tty_lock();
+       }
+}
+
+/*
+ * The unthrottle routine is called by the line discipline to signal
+ * that it can receive more characters.  For PTY's, the TTY_THROTTLED
+ * flag is always set, to force the line discipline to always call the
+ * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
+ * characters in the queue.  This is necessary since each time this
+ * happens, we need to wake up any sleeping processes that could be
+ * (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
+ * for the pty buffer to be drained.
+ */
+static void pty_unthrottle(struct tty_struct *tty)
+{
+       tty_wakeup(tty->link);
+       set_bit(TTY_THROTTLED, &tty->flags);
+}
+
+/**
+ *     pty_space       -       report space left for writing
+ *     @to: tty we are writing into
+ *
+ *     The tty buffers allow 64K but we sneak a peak and clip at 8K this
+ *     allows a lot of overspill room for echo and other fun messes to
+ *     be handled properly
+ */
+
+static int pty_space(struct tty_struct *to)
+{
+       int n = 8192 - to->buf.memory_used;
+       if (n < 0)
+               return 0;
+       return n;
+}
+
+/**
+ *     pty_write               -       write to a pty
+ *     @tty: the tty we write from
+ *     @buf: kernel buffer of data
+ *     @count: bytes to write
+ *
+ *     Our "hardware" write method. Data is coming from the ldisc which
+ *     may be in a non sleeping state. We simply throw this at the other
+ *     end of the link as if we were an IRQ handler receiving stuff for
+ *     the other side of the pty/tty pair.
+ */
+
+static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
+{
+       struct tty_struct *to = tty->link;
+
+       if (tty->stopped)
+               return 0;
+
+       if (c > 0) {
+               /* Stuff the data into the input queue of the other end */
+               c = tty_insert_flip_string(to, buf, c);
+               /* And shovel */
+               if (c) {
+                       tty_flip_buffer_push(to);
+                       tty_wakeup(tty);
+               }
+       }
+       return c;
+}
+
+/**
+ *     pty_write_room  -       write space
+ *     @tty: tty we are writing from
+ *
+ *     Report how many bytes the ldisc can send into the queue for
+ *     the other device.
+ */
+
+static int pty_write_room(struct tty_struct *tty)
+{
+       if (tty->stopped)
+               return 0;
+       return pty_space(tty->link);
+}
+
+/**
+ *     pty_chars_in_buffer     -       characters currently in our tx queue
+ *     @tty: our tty
+ *
+ *     Report how much we have in the transmit queue. As everything is
+ *     instantly at the other end this is easy to implement.
+ */
+
+static int pty_chars_in_buffer(struct tty_struct *tty)
+{
+       return 0;
+}
+
+/* Set the lock flag on a pty */
+static int pty_set_lock(struct tty_struct *tty, int __user *arg)
+{
+       int val;
+       if (get_user(val, arg))
+               return -EFAULT;
+       if (val)
+               set_bit(TTY_PTY_LOCK, &tty->flags);
+       else
+               clear_bit(TTY_PTY_LOCK, &tty->flags);
+       return 0;
+}
+
+/* Send a signal to the slave */
+static int pty_signal(struct tty_struct *tty, int sig)
+{
+       unsigned long flags;
+       struct pid *pgrp;
+
+       if (tty->link) {
+               spin_lock_irqsave(&tty->link->ctrl_lock, flags);
+               pgrp = get_pid(tty->link->pgrp);
+               spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
+
+               kill_pgrp(pgrp, sig, 1);
+               put_pid(pgrp);
+       }
+       return 0;
+}
+
+static void pty_flush_buffer(struct tty_struct *tty)
+{
+       struct tty_struct *to = tty->link;
+       unsigned long flags;
+
+       if (!to)
+               return;
+       /* tty_buffer_flush(to); FIXME */
+       if (to->packet) {
+               spin_lock_irqsave(&tty->ctrl_lock, flags);
+               tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
+               wake_up_interruptible(&to->read_wait);
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+       }
+}
+
+static int pty_open(struct tty_struct *tty, struct file *filp)
+{
+       int     retval = -ENODEV;
+
+       if (!tty || !tty->link)
+               goto out;
+
+       retval = -EIO;
+       if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+               goto out;
+       if (test_bit(TTY_PTY_LOCK, &tty->link->flags))
+               goto out;
+       if (tty->link->count != 1)
+               goto out;
+
+       clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
+       set_bit(TTY_THROTTLED, &tty->flags);
+       retval = 0;
+out:
+       return retval;
+}
+
+static void pty_set_termios(struct tty_struct *tty,
+                                       struct ktermios *old_termios)
+{
+       tty->termios->c_cflag &= ~(CSIZE | PARENB);
+       tty->termios->c_cflag |= (CS8 | CREAD);
+}
+
+/**
+ *     pty_do_resize           -       resize event
+ *     @tty: tty being resized
+ *     @ws: window size being set.
+ *
+ *     Update the termios variables and send the necessary signals to
+ *     peform a terminal resize correctly
+ */
+
+int pty_resize(struct tty_struct *tty,  struct winsize *ws)
+{
+       struct pid *pgrp, *rpgrp;
+       unsigned long flags;
+       struct tty_struct *pty = tty->link;
+
+       /* For a PTY we need to lock the tty side */
+       mutex_lock(&tty->termios_mutex);
+       if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
+               goto done;
+
+       /* Get the PID values and reference them so we can
+          avoid holding the tty ctrl lock while sending signals.
+          We need to lock these individually however. */
+
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       pgrp = get_pid(tty->pgrp);
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+       spin_lock_irqsave(&pty->ctrl_lock, flags);
+       rpgrp = get_pid(pty->pgrp);
+       spin_unlock_irqrestore(&pty->ctrl_lock, flags);
+
+       if (pgrp)
+               kill_pgrp(pgrp, SIGWINCH, 1);
+       if (rpgrp != pgrp && rpgrp)
+               kill_pgrp(rpgrp, SIGWINCH, 1);
+
+       put_pid(pgrp);
+       put_pid(rpgrp);
+
+       tty->winsize = *ws;
+       pty->winsize = *ws;     /* Never used so will go away soon */
+done:
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
+}
+
+/* Traditional BSD devices */
+#ifdef CONFIG_LEGACY_PTYS
+
+static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+       struct tty_struct *o_tty;
+       int idx = tty->index;
+       int retval;
+
+       o_tty = alloc_tty_struct();
+       if (!o_tty)
+               return -ENOMEM;
+       if (!try_module_get(driver->other->owner)) {
+               /* This cannot in fact currently happen */
+               free_tty_struct(o_tty);
+               return -ENOMEM;
+       }
+       initialize_tty_struct(o_tty, driver->other, idx);
+
+       /* We always use new tty termios data so we can do this
+          the easy way .. */
+       retval = tty_init_termios(tty);
+       if (retval)
+               goto free_mem_out;
+
+       retval = tty_init_termios(o_tty);
+       if (retval) {
+               tty_free_termios(tty);
+               goto free_mem_out;
+       }
+
+       /*
+        * Everything allocated ... set up the o_tty structure.
+        */
+       driver->other->ttys[idx] = o_tty;
+       tty_driver_kref_get(driver->other);
+       if (driver->subtype == PTY_TYPE_MASTER)
+               o_tty->count++;
+       /* Establish the links in both directions */
+       tty->link   = o_tty;
+       o_tty->link = tty;
+
+       tty_driver_kref_get(driver);
+       tty->count++;
+       driver->ttys[idx] = tty;
+       return 0;
+free_mem_out:
+       module_put(o_tty->driver->owner);
+       free_tty_struct(o_tty);
+       return -ENOMEM;
+}
+
+static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
+               return pty_set_lock(tty, (int __user *) arg);
+       case TIOCSIG:    /* Send signal to other side of pty */
+               return pty_signal(tty, (int) arg);
+       }
+       return -ENOIOCTLCMD;
+}
+
+static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
+module_param(legacy_count, int, 0);
+
+/*
+ * The master side of a pty can do TIOCSPTLCK and thus
+ * has pty_bsd_ioctl.
+ */
+static const struct tty_operations master_pty_ops_bsd = {
+       .install = pty_install,
+       .open = pty_open,
+       .close = pty_close,
+       .write = pty_write,
+       .write_room = pty_write_room,
+       .flush_buffer = pty_flush_buffer,
+       .chars_in_buffer = pty_chars_in_buffer,
+       .unthrottle = pty_unthrottle,
+       .set_termios = pty_set_termios,
+       .ioctl = pty_bsd_ioctl,
+       .resize = pty_resize
+};
+
+static const struct tty_operations slave_pty_ops_bsd = {
+       .install = pty_install,
+       .open = pty_open,
+       .close = pty_close,
+       .write = pty_write,
+       .write_room = pty_write_room,
+       .flush_buffer = pty_flush_buffer,
+       .chars_in_buffer = pty_chars_in_buffer,
+       .unthrottle = pty_unthrottle,
+       .set_termios = pty_set_termios,
+       .resize = pty_resize
+};
+
+static void __init legacy_pty_init(void)
+{
+       struct tty_driver *pty_driver, *pty_slave_driver;
+
+       if (legacy_count <= 0)
+               return;
+
+       pty_driver = alloc_tty_driver(legacy_count);
+       if (!pty_driver)
+               panic("Couldn't allocate pty driver");
+
+       pty_slave_driver = alloc_tty_driver(legacy_count);
+       if (!pty_slave_driver)
+               panic("Couldn't allocate pty slave driver");
+
+       pty_driver->owner = THIS_MODULE;
+       pty_driver->driver_name = "pty_master";
+       pty_driver->name = "pty";
+       pty_driver->major = PTY_MASTER_MAJOR;
+       pty_driver->minor_start = 0;
+       pty_driver->type = TTY_DRIVER_TYPE_PTY;
+       pty_driver->subtype = PTY_TYPE_MASTER;
+       pty_driver->init_termios = tty_std_termios;
+       pty_driver->init_termios.c_iflag = 0;
+       pty_driver->init_termios.c_oflag = 0;
+       pty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
+       pty_driver->init_termios.c_lflag = 0;
+       pty_driver->init_termios.c_ispeed = 38400;
+       pty_driver->init_termios.c_ospeed = 38400;
+       pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
+       pty_driver->other = pty_slave_driver;
+       tty_set_operations(pty_driver, &master_pty_ops_bsd);
+
+       pty_slave_driver->owner = THIS_MODULE;
+       pty_slave_driver->driver_name = "pty_slave";
+       pty_slave_driver->name = "ttyp";
+       pty_slave_driver->major = PTY_SLAVE_MAJOR;
+       pty_slave_driver->minor_start = 0;
+       pty_slave_driver->type = TTY_DRIVER_TYPE_PTY;
+       pty_slave_driver->subtype = PTY_TYPE_SLAVE;
+       pty_slave_driver->init_termios = tty_std_termios;
+       pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
+       pty_slave_driver->init_termios.c_ispeed = 38400;
+       pty_slave_driver->init_termios.c_ospeed = 38400;
+       pty_slave_driver->flags = TTY_DRIVER_RESET_TERMIOS |
+                                       TTY_DRIVER_REAL_RAW;
+       pty_slave_driver->other = pty_driver;
+       tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd);
+
+       if (tty_register_driver(pty_driver))
+               panic("Couldn't register pty driver");
+       if (tty_register_driver(pty_slave_driver))
+               panic("Couldn't register pty slave driver");
+}
+#else
+static inline void legacy_pty_init(void) { }
+#endif
+
+/* Unix98 devices */
+#ifdef CONFIG_UNIX98_PTYS
+/*
+ * sysctl support for setting limits on the number of Unix98 ptys allocated.
+ * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
+ */
+int pty_limit = NR_UNIX98_PTY_DEFAULT;
+static int pty_limit_min;
+static int pty_limit_max = NR_UNIX98_PTY_MAX;
+static int pty_count;
+
+static struct cdev ptmx_cdev;
+
+static struct ctl_table pty_table[] = {
+       {
+               .procname       = "max",
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .data           = &pty_limit,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &pty_limit_min,
+               .extra2         = &pty_limit_max,
+       }, {
+               .procname       = "nr",
+               .maxlen         = sizeof(int),
+               .mode           = 0444,
+               .data           = &pty_count,
+               .proc_handler   = proc_dointvec,
+       }, 
+       {}
+};
+
+static struct ctl_table pty_kern_table[] = {
+       {
+               .procname       = "pty",
+               .mode           = 0555,
+               .child          = pty_table,
+       },
+       {}
+};
+
+static struct ctl_table pty_root_table[] = {
+       {
+               .procname       = "kernel",
+               .mode           = 0555,
+               .child          = pty_kern_table,
+       },
+       {}
+};
+
+
+static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
+                           unsigned int cmd, unsigned long arg)
+{
+       switch (cmd) {
+       case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
+               return pty_set_lock(tty, (int __user *)arg);
+       case TIOCGPTN: /* Get PT Number */
+               return put_user(tty->index, (unsigned int __user *)arg);
+       case TIOCSIG:    /* Send signal to other side of pty */
+               return pty_signal(tty, (int) arg);
+       }
+
+       return -ENOIOCTLCMD;
+}
+
+/**
+ *     ptm_unix98_lookup       -       find a pty master
+ *     @driver: ptm driver
+ *     @idx: tty index
+ *
+ *     Look up a pty master device. Called under the tty_mutex for now.
+ *     This provides our locking.
+ */
+
+static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
+               struct inode *ptm_inode, int idx)
+{
+       struct tty_struct *tty = devpts_get_tty(ptm_inode, idx);
+       if (tty)
+               tty = tty->link;
+       return tty;
+}
+
+/**
+ *     pts_unix98_lookup       -       find a pty slave
+ *     @driver: pts driver
+ *     @idx: tty index
+ *
+ *     Look up a pty master device. Called under the tty_mutex for now.
+ *     This provides our locking.
+ */
+
+static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
+               struct inode *pts_inode, int idx)
+{
+       struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
+       /* Master must be open before slave */
+       if (!tty)
+               return ERR_PTR(-EIO);
+       return tty;
+}
+
+static void pty_unix98_shutdown(struct tty_struct *tty)
+{
+       /* We have our own method as we don't use the tty index */
+       kfree(tty->termios);
+}
+
+/* We have no need to install and remove our tty objects as devpts does all
+   the work for us */
+
+static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+       struct tty_struct *o_tty;
+       int idx = tty->index;
+
+       o_tty = alloc_tty_struct();
+       if (!o_tty)
+               return -ENOMEM;
+       if (!try_module_get(driver->other->owner)) {
+               /* This cannot in fact currently happen */
+               free_tty_struct(o_tty);
+               return -ENOMEM;
+       }
+       initialize_tty_struct(o_tty, driver->other, idx);
+
+       tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+       if (tty->termios == NULL)
+               goto free_mem_out;
+       *tty->termios = driver->init_termios;
+       tty->termios_locked = tty->termios + 1;
+
+       o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+       if (o_tty->termios == NULL)
+               goto free_mem_out;
+       *o_tty->termios = driver->other->init_termios;
+       o_tty->termios_locked = o_tty->termios + 1;
+
+       tty_driver_kref_get(driver->other);
+       if (driver->subtype == PTY_TYPE_MASTER)
+               o_tty->count++;
+       /* Establish the links in both directions */
+       tty->link   = o_tty;
+       o_tty->link = tty;
+       /*
+        * All structures have been allocated, so now we install them.
+        * Failures after this point use release_tty to clean up, so
+        * there's no need to null out the local pointers.
+        */
+       tty_driver_kref_get(driver);
+       tty->count++;
+       pty_count++;
+       return 0;
+free_mem_out:
+       kfree(o_tty->termios);
+       module_put(o_tty->driver->owner);
+       free_tty_struct(o_tty);
+       kfree(tty->termios);
+       return -ENOMEM;
+}
+
+static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
+{
+       pty_count--;
+}
+
+static const struct tty_operations ptm_unix98_ops = {
+       .lookup = ptm_unix98_lookup,
+       .install = pty_unix98_install,
+       .remove = pty_unix98_remove,
+       .open = pty_open,
+       .close = pty_close,
+       .write = pty_write,
+       .write_room = pty_write_room,
+       .flush_buffer = pty_flush_buffer,
+       .chars_in_buffer = pty_chars_in_buffer,
+       .unthrottle = pty_unthrottle,
+       .set_termios = pty_set_termios,
+       .ioctl = pty_unix98_ioctl,
+       .shutdown = pty_unix98_shutdown,
+       .resize = pty_resize
+};
+
+static const struct tty_operations pty_unix98_ops = {
+       .lookup = pts_unix98_lookup,
+       .install = pty_unix98_install,
+       .remove = pty_unix98_remove,
+       .open = pty_open,
+       .close = pty_close,
+       .write = pty_write,
+       .write_room = pty_write_room,
+       .flush_buffer = pty_flush_buffer,
+       .chars_in_buffer = pty_chars_in_buffer,
+       .unthrottle = pty_unthrottle,
+       .set_termios = pty_set_termios,
+       .shutdown = pty_unix98_shutdown
+};
+
+/**
+ *     ptmx_open               -       open a unix 98 pty master
+ *     @inode: inode of device file
+ *     @filp: file pointer to tty
+ *
+ *     Allocate a unix98 pty master device from the ptmx driver.
+ *
+ *     Locking: tty_mutex protects the init_dev work. tty->count should
+ *             protect the rest.
+ *             allocated_ptys_lock handles the list of free pty numbers
+ */
+
+static int ptmx_open(struct inode *inode, struct file *filp)
+{
+       struct tty_struct *tty;
+       int retval;
+       int index;
+
+       nonseekable_open(inode, filp);
+
+       /* find a device that is not in use. */
+       tty_lock();
+       index = devpts_new_index(inode);
+       tty_unlock();
+       if (index < 0)
+               return index;
+
+       mutex_lock(&tty_mutex);
+       tty_lock();
+       tty = tty_init_dev(ptm_driver, index, 1);
+       mutex_unlock(&tty_mutex);
+
+       if (IS_ERR(tty)) {
+               retval = PTR_ERR(tty);
+               goto out;
+       }
+
+       set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
+
+       retval = tty_add_file(tty, filp);
+       if (retval)
+               goto out;
+
+       retval = devpts_pty_new(inode, tty->link);
+       if (retval)
+               goto out1;
+
+       retval = ptm_driver->ops->open(tty, filp);
+       if (retval)
+               goto out2;
+out1:
+       tty_unlock();
+       return retval;
+out2:
+       tty_unlock();
+       tty_release(inode, filp);
+       return retval;
+out:
+       devpts_kill_index(inode, index);
+       tty_unlock();
+       return retval;
+}
+
+static struct file_operations ptmx_fops;
+
+static void __init unix98_pty_init(void)
+{
+       ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
+       if (!ptm_driver)
+               panic("Couldn't allocate Unix98 ptm driver");
+       pts_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
+       if (!pts_driver)
+               panic("Couldn't allocate Unix98 pts driver");
+
+       ptm_driver->owner = THIS_MODULE;
+       ptm_driver->driver_name = "pty_master";
+       ptm_driver->name = "ptm";
+       ptm_driver->major = UNIX98_PTY_MASTER_MAJOR;
+       ptm_driver->minor_start = 0;
+       ptm_driver->type = TTY_DRIVER_TYPE_PTY;
+       ptm_driver->subtype = PTY_TYPE_MASTER;
+       ptm_driver->init_termios = tty_std_termios;
+       ptm_driver->init_termios.c_iflag = 0;
+       ptm_driver->init_termios.c_oflag = 0;
+       ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
+       ptm_driver->init_termios.c_lflag = 0;
+       ptm_driver->init_termios.c_ispeed = 38400;
+       ptm_driver->init_termios.c_ospeed = 38400;
+       ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
+               TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
+       ptm_driver->other = pts_driver;
+       tty_set_operations(ptm_driver, &ptm_unix98_ops);
+
+       pts_driver->owner = THIS_MODULE;
+       pts_driver->driver_name = "pty_slave";
+       pts_driver->name = "pts";
+       pts_driver->major = UNIX98_PTY_SLAVE_MAJOR;
+       pts_driver->minor_start = 0;
+       pts_driver->type = TTY_DRIVER_TYPE_PTY;
+       pts_driver->subtype = PTY_TYPE_SLAVE;
+       pts_driver->init_termios = tty_std_termios;
+       pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
+       pts_driver->init_termios.c_ispeed = 38400;
+       pts_driver->init_termios.c_ospeed = 38400;
+       pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
+               TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
+       pts_driver->other = ptm_driver;
+       tty_set_operations(pts_driver, &pty_unix98_ops);
+
+       if (tty_register_driver(ptm_driver))
+               panic("Couldn't register Unix98 ptm driver");
+       if (tty_register_driver(pts_driver))
+               panic("Couldn't register Unix98 pts driver");
+
+       register_sysctl_table(pty_root_table);
+
+       /* Now create the /dev/ptmx special device */
+       tty_default_fops(&ptmx_fops);
+       ptmx_fops.open = ptmx_open;
+
+       cdev_init(&ptmx_cdev, &ptmx_fops);
+       if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
+           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
+               panic("Couldn't register /dev/ptmx driver\n");
+       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
+}
+
+#else
+static inline void unix98_pty_init(void) { }
+#endif
+
+static int __init pty_init(void)
+{
+       legacy_pty_init();
+       unix98_pty_init();
+       return 0;
+}
+module_init(pty_init);
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
new file mode 100644 (file)
index 0000000..eaa5d3e
--- /dev/null
@@ -0,0 +1,811 @@
+/*
+ *     Linux Magic System Request Key Hacks
+ *
+ *     (c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *     based on ideas by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>
+ *
+ *     (c) 2000 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
+ *     overhauled to use key registration
+ *     based upon discusions in irc://irc.openprojects.net/#kernelnewbies
+ *
+ *     Copyright (c) 2010 Dmitry Torokhov
+ *     Input handler conversion
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/reboot.h>
+#include <linux/sysrq.h>
+#include <linux/kbd_kern.h>
+#include <linux/proc_fs.h>
+#include <linux/nmi.h>
+#include <linux/quotaops.h>
+#include <linux/perf_event.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/suspend.h>
+#include <linux/writeback.h>
+#include <linux/buffer_head.h>         /* for fsync_bdev() */
+#include <linux/swap.h>
+#include <linux/spinlock.h>
+#include <linux/vt_kern.h>
+#include <linux/workqueue.h>
+#include <linux/hrtimer.h>
+#include <linux/oom.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+
+#include <asm/ptrace.h>
+#include <asm/irq_regs.h>
+
+/* Whether we react on sysrq keys or just ignore them */
+static int __read_mostly sysrq_enabled = 1;
+static bool __read_mostly sysrq_always_enabled;
+
+static bool sysrq_on(void)
+{
+       return sysrq_enabled || sysrq_always_enabled;
+}
+
+/*
+ * A value of 1 means 'all', other nonzero values are an op mask:
+ */
+static bool sysrq_on_mask(int mask)
+{
+       return sysrq_always_enabled ||
+              sysrq_enabled == 1 ||
+              (sysrq_enabled & mask);
+}
+
+static int __init sysrq_always_enabled_setup(char *str)
+{
+       sysrq_always_enabled = true;
+       pr_info("sysrq always enabled.\n");
+
+       return 1;
+}
+
+__setup("sysrq_always_enabled", sysrq_always_enabled_setup);
+
+
+static void sysrq_handle_loglevel(int key)
+{
+       int i;
+
+       i = key - '0';
+       console_loglevel = 7;
+       printk("Loglevel set to %d\n", i);
+       console_loglevel = i;
+}
+static struct sysrq_key_op sysrq_loglevel_op = {
+       .handler        = sysrq_handle_loglevel,
+       .help_msg       = "loglevel(0-9)",
+       .action_msg     = "Changing Loglevel",
+       .enable_mask    = SYSRQ_ENABLE_LOG,
+};
+
+#ifdef CONFIG_VT
+static void sysrq_handle_SAK(int key)
+{
+       struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
+       schedule_work(SAK_work);
+}
+static struct sysrq_key_op sysrq_SAK_op = {
+       .handler        = sysrq_handle_SAK,
+       .help_msg       = "saK",
+       .action_msg     = "SAK",
+       .enable_mask    = SYSRQ_ENABLE_KEYBOARD,
+};
+#else
+#define sysrq_SAK_op (*(struct sysrq_key_op *)NULL)
+#endif
+
+#ifdef CONFIG_VT
+static void sysrq_handle_unraw(int key)
+{
+       struct kbd_struct *kbd = &kbd_table[fg_console];
+
+       if (kbd)
+               kbd->kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
+}
+static struct sysrq_key_op sysrq_unraw_op = {
+       .handler        = sysrq_handle_unraw,
+       .help_msg       = "unRaw",
+       .action_msg     = "Keyboard mode set to system default",
+       .enable_mask    = SYSRQ_ENABLE_KEYBOARD,
+};
+#else
+#define sysrq_unraw_op (*(struct sysrq_key_op *)NULL)
+#endif /* CONFIG_VT */
+
+static void sysrq_handle_crash(int key)
+{
+       char *killer = NULL;
+
+       panic_on_oops = 1;      /* force panic */
+       wmb();
+       *killer = 1;
+}
+static struct sysrq_key_op sysrq_crash_op = {
+       .handler        = sysrq_handle_crash,
+       .help_msg       = "Crash",
+       .action_msg     = "Trigger a crash",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+
+static void sysrq_handle_reboot(int key)
+{
+       lockdep_off();
+       local_irq_enable();
+       emergency_restart();
+}
+static struct sysrq_key_op sysrq_reboot_op = {
+       .handler        = sysrq_handle_reboot,
+       .help_msg       = "reBoot",
+       .action_msg     = "Resetting",
+       .enable_mask    = SYSRQ_ENABLE_BOOT,
+};
+
+static void sysrq_handle_sync(int key)
+{
+       emergency_sync();
+}
+static struct sysrq_key_op sysrq_sync_op = {
+       .handler        = sysrq_handle_sync,
+       .help_msg       = "Sync",
+       .action_msg     = "Emergency Sync",
+       .enable_mask    = SYSRQ_ENABLE_SYNC,
+};
+
+static void sysrq_handle_show_timers(int key)
+{
+       sysrq_timer_list_show();
+}
+
+static struct sysrq_key_op sysrq_show_timers_op = {
+       .handler        = sysrq_handle_show_timers,
+       .help_msg       = "show-all-timers(Q)",
+       .action_msg     = "Show clockevent devices & pending hrtimers (no others)",
+};
+
+static void sysrq_handle_mountro(int key)
+{
+       emergency_remount();
+}
+static struct sysrq_key_op sysrq_mountro_op = {
+       .handler        = sysrq_handle_mountro,
+       .help_msg       = "Unmount",
+       .action_msg     = "Emergency Remount R/O",
+       .enable_mask    = SYSRQ_ENABLE_REMOUNT,
+};
+
+#ifdef CONFIG_LOCKDEP
+static void sysrq_handle_showlocks(int key)
+{
+       debug_show_all_locks();
+}
+
+static struct sysrq_key_op sysrq_showlocks_op = {
+       .handler        = sysrq_handle_showlocks,
+       .help_msg       = "show-all-locks(D)",
+       .action_msg     = "Show Locks Held",
+};
+#else
+#define sysrq_showlocks_op (*(struct sysrq_key_op *)NULL)
+#endif
+
+#ifdef CONFIG_SMP
+static DEFINE_SPINLOCK(show_lock);
+
+static void showacpu(void *dummy)
+{
+       unsigned long flags;
+
+       /* Idle CPUs have no interesting backtrace. */
+       if (idle_cpu(smp_processor_id()))
+               return;
+
+       spin_lock_irqsave(&show_lock, flags);
+       printk(KERN_INFO "CPU%d:\n", smp_processor_id());
+       show_stack(NULL, NULL);
+       spin_unlock_irqrestore(&show_lock, flags);
+}
+
+static void sysrq_showregs_othercpus(struct work_struct *dummy)
+{
+       smp_call_function(showacpu, NULL, 0);
+}
+
+static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus);
+
+static void sysrq_handle_showallcpus(int key)
+{
+       /*
+        * Fall back to the workqueue based printing if the
+        * backtrace printing did not succeed or the
+        * architecture has no support for it:
+        */
+       if (!trigger_all_cpu_backtrace()) {
+               struct pt_regs *regs = get_irq_regs();
+
+               if (regs) {
+                       printk(KERN_INFO "CPU%d:\n", smp_processor_id());
+                       show_regs(regs);
+               }
+               schedule_work(&sysrq_showallcpus);
+       }
+}
+
+static struct sysrq_key_op sysrq_showallcpus_op = {
+       .handler        = sysrq_handle_showallcpus,
+       .help_msg       = "show-backtrace-all-active-cpus(L)",
+       .action_msg     = "Show backtrace of all active CPUs",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+#endif
+
+static void sysrq_handle_showregs(int key)
+{
+       struct pt_regs *regs = get_irq_regs();
+       if (regs)
+               show_regs(regs);
+       perf_event_print_debug();
+}
+static struct sysrq_key_op sysrq_showregs_op = {
+       .handler        = sysrq_handle_showregs,
+       .help_msg       = "show-registers(P)",
+       .action_msg     = "Show Regs",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+
+static void sysrq_handle_showstate(int key)
+{
+       show_state();
+}
+static struct sysrq_key_op sysrq_showstate_op = {
+       .handler        = sysrq_handle_showstate,
+       .help_msg       = "show-task-states(T)",
+       .action_msg     = "Show State",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+
+static void sysrq_handle_showstate_blocked(int key)
+{
+       show_state_filter(TASK_UNINTERRUPTIBLE);
+}
+static struct sysrq_key_op sysrq_showstate_blocked_op = {
+       .handler        = sysrq_handle_showstate_blocked,
+       .help_msg       = "show-blocked-tasks(W)",
+       .action_msg     = "Show Blocked State",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+
+#ifdef CONFIG_TRACING
+#include <linux/ftrace.h>
+
+static void sysrq_ftrace_dump(int key)
+{
+       ftrace_dump(DUMP_ALL);
+}
+static struct sysrq_key_op sysrq_ftrace_dump_op = {
+       .handler        = sysrq_ftrace_dump,
+       .help_msg       = "dump-ftrace-buffer(Z)",
+       .action_msg     = "Dump ftrace buffer",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+#else
+#define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)NULL)
+#endif
+
+static void sysrq_handle_showmem(int key)
+{
+       show_mem();
+}
+static struct sysrq_key_op sysrq_showmem_op = {
+       .handler        = sysrq_handle_showmem,
+       .help_msg       = "show-memory-usage(M)",
+       .action_msg     = "Show Memory",
+       .enable_mask    = SYSRQ_ENABLE_DUMP,
+};
+
+/*
+ * Signal sysrq helper function.  Sends a signal to all user processes.
+ */
+static void send_sig_all(int sig)
+{
+       struct task_struct *p;
+
+       for_each_process(p) {
+               if (p->mm && !is_global_init(p))
+                       /* Not swapper, init nor kernel thread */
+                       force_sig(sig, p);
+       }
+}
+
+static void sysrq_handle_term(int key)
+{
+       send_sig_all(SIGTERM);
+       console_loglevel = 8;
+}
+static struct sysrq_key_op sysrq_term_op = {
+       .handler        = sysrq_handle_term,
+       .help_msg       = "terminate-all-tasks(E)",
+       .action_msg     = "Terminate All Tasks",
+       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
+};
+
+static void moom_callback(struct work_struct *ignored)
+{
+       out_of_memory(node_zonelist(0, GFP_KERNEL), GFP_KERNEL, 0, NULL);
+}
+
+static DECLARE_WORK(moom_work, moom_callback);
+
+static void sysrq_handle_moom(int key)
+{
+       schedule_work(&moom_work);
+}
+static struct sysrq_key_op sysrq_moom_op = {
+       .handler        = sysrq_handle_moom,
+       .help_msg       = "memory-full-oom-kill(F)",
+       .action_msg     = "Manual OOM execution",
+       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
+};
+
+#ifdef CONFIG_BLOCK
+static void sysrq_handle_thaw(int key)
+{
+       emergency_thaw_all();
+}
+static struct sysrq_key_op sysrq_thaw_op = {
+       .handler        = sysrq_handle_thaw,
+       .help_msg       = "thaw-filesystems(J)",
+       .action_msg     = "Emergency Thaw of all frozen filesystems",
+       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
+};
+#endif
+
+static void sysrq_handle_kill(int key)
+{
+       send_sig_all(SIGKILL);
+       console_loglevel = 8;
+}
+static struct sysrq_key_op sysrq_kill_op = {
+       .handler        = sysrq_handle_kill,
+       .help_msg       = "kill-all-tasks(I)",
+       .action_msg     = "Kill All Tasks",
+       .enable_mask    = SYSRQ_ENABLE_SIGNAL,
+};
+
+static void sysrq_handle_unrt(int key)
+{
+       normalize_rt_tasks();
+}
+static struct sysrq_key_op sysrq_unrt_op = {
+       .handler        = sysrq_handle_unrt,
+       .help_msg       = "nice-all-RT-tasks(N)",
+       .action_msg     = "Nice All RT Tasks",
+       .enable_mask    = SYSRQ_ENABLE_RTNICE,
+};
+
+/* Key Operations table and lock */
+static DEFINE_SPINLOCK(sysrq_key_table_lock);
+
+static struct sysrq_key_op *sysrq_key_table[36] = {
+       &sysrq_loglevel_op,             /* 0 */
+       &sysrq_loglevel_op,             /* 1 */
+       &sysrq_loglevel_op,             /* 2 */
+       &sysrq_loglevel_op,             /* 3 */
+       &sysrq_loglevel_op,             /* 4 */
+       &sysrq_loglevel_op,             /* 5 */
+       &sysrq_loglevel_op,             /* 6 */
+       &sysrq_loglevel_op,             /* 7 */
+       &sysrq_loglevel_op,             /* 8 */
+       &sysrq_loglevel_op,             /* 9 */
+
+       /*
+        * a: Don't use for system provided sysrqs, it is handled specially on
+        * sparc and will never arrive.
+        */
+       NULL,                           /* a */
+       &sysrq_reboot_op,               /* b */
+       &sysrq_crash_op,                /* c & ibm_emac driver debug */
+       &sysrq_showlocks_op,            /* d */
+       &sysrq_term_op,                 /* e */
+       &sysrq_moom_op,                 /* f */
+       /* g: May be registered for the kernel debugger */
+       NULL,                           /* g */
+       NULL,                           /* h - reserved for help */
+       &sysrq_kill_op,                 /* i */
+#ifdef CONFIG_BLOCK
+       &sysrq_thaw_op,                 /* j */
+#else
+       NULL,                           /* j */
+#endif
+       &sysrq_SAK_op,                  /* k */
+#ifdef CONFIG_SMP
+       &sysrq_showallcpus_op,          /* l */
+#else
+       NULL,                           /* l */
+#endif
+       &sysrq_showmem_op,              /* m */
+       &sysrq_unrt_op,                 /* n */
+       /* o: This will often be registered as 'Off' at init time */
+       NULL,                           /* o */
+       &sysrq_showregs_op,             /* p */
+       &sysrq_show_timers_op,          /* q */
+       &sysrq_unraw_op,                /* r */
+       &sysrq_sync_op,                 /* s */
+       &sysrq_showstate_op,            /* t */
+       &sysrq_mountro_op,              /* u */
+       /* v: May be registered for frame buffer console restore */
+       NULL,                           /* v */
+       &sysrq_showstate_blocked_op,    /* w */
+       /* x: May be registered on ppc/powerpc for xmon */
+       NULL,                           /* x */
+       /* y: May be registered on sparc64 for global register dump */
+       NULL,                           /* y */
+       &sysrq_ftrace_dump_op,          /* z */
+};
+
+/* key2index calculation, -1 on invalid index */
+static int sysrq_key_table_key2index(int key)
+{
+       int retval;
+
+       if ((key >= '0') && (key <= '9'))
+               retval = key - '0';
+       else if ((key >= 'a') && (key <= 'z'))
+               retval = key + 10 - 'a';
+       else
+               retval = -1;
+       return retval;
+}
+
+/*
+ * get and put functions for the table, exposed to modules.
+ */
+struct sysrq_key_op *__sysrq_get_key_op(int key)
+{
+        struct sysrq_key_op *op_p = NULL;
+        int i;
+
+       i = sysrq_key_table_key2index(key);
+       if (i != -1)
+               op_p = sysrq_key_table[i];
+
+        return op_p;
+}
+
+static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p)
+{
+        int i = sysrq_key_table_key2index(key);
+
+        if (i != -1)
+                sysrq_key_table[i] = op_p;
+}
+
+void __handle_sysrq(int key, bool check_mask)
+{
+       struct sysrq_key_op *op_p;
+       int orig_log_level;
+       int i;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sysrq_key_table_lock, flags);
+       /*
+        * Raise the apparent loglevel to maximum so that the sysrq header
+        * is shown to provide the user with positive feedback.  We do not
+        * simply emit this at KERN_EMERG as that would change message
+        * routing in the consumers of /proc/kmsg.
+        */
+       orig_log_level = console_loglevel;
+       console_loglevel = 7;
+       printk(KERN_INFO "SysRq : ");
+
+        op_p = __sysrq_get_key_op(key);
+        if (op_p) {
+               /*
+                * Should we check for enabled operations (/proc/sysrq-trigger
+                * should not) and is the invoked operation enabled?
+                */
+               if (!check_mask || sysrq_on_mask(op_p->enable_mask)) {
+                       printk("%s\n", op_p->action_msg);
+                       console_loglevel = orig_log_level;
+                       op_p->handler(key);
+               } else {
+                       printk("This sysrq operation is disabled.\n");
+               }
+       } else {
+               printk("HELP : ");
+               /* Only print the help msg once per handler */
+               for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) {
+                       if (sysrq_key_table[i]) {
+                               int j;
+
+                               for (j = 0; sysrq_key_table[i] !=
+                                               sysrq_key_table[j]; j++)
+                                       ;
+                               if (j != i)
+                                       continue;
+                               printk("%s ", sysrq_key_table[i]->help_msg);
+                       }
+               }
+               printk("\n");
+               console_loglevel = orig_log_level;
+       }
+       spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
+}
+
+void handle_sysrq(int key)
+{
+       if (sysrq_on())
+               __handle_sysrq(key, true);
+}
+EXPORT_SYMBOL(handle_sysrq);
+
+#ifdef CONFIG_INPUT
+
+/* Simple translation table for the SysRq keys */
+static const unsigned char sysrq_xlate[KEY_MAX + 1] =
+        "\000\0331234567890-=\177\t"                    /* 0x00 - 0x0f */
+        "qwertyuiop[]\r\000as"                          /* 0x10 - 0x1f */
+        "dfghjkl;'`\000\\zxcv"                          /* 0x20 - 0x2f */
+        "bnm,./\000*\000 \000\201\202\203\204\205"      /* 0x30 - 0x3f */
+        "\206\207\210\211\212\000\000789-456+1"         /* 0x40 - 0x4f */
+        "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
+        "\r\000/";                                      /* 0x60 - 0x6f */
+
+static bool sysrq_down;
+static int sysrq_alt_use;
+static int sysrq_alt;
+static DEFINE_SPINLOCK(sysrq_event_lock);
+
+static bool sysrq_filter(struct input_handle *handle, unsigned int type,
+                        unsigned int code, int value)
+{
+       bool suppress;
+
+       /* We are called with interrupts disabled, just take the lock */
+       spin_lock(&sysrq_event_lock);
+
+       if (type != EV_KEY)
+               goto out;
+
+       switch (code) {
+
+       case KEY_LEFTALT:
+       case KEY_RIGHTALT:
+               if (value)
+                       sysrq_alt = code;
+               else {
+                       if (sysrq_down && code == sysrq_alt_use)
+                               sysrq_down = false;
+
+                       sysrq_alt = 0;
+               }
+               break;
+
+       case KEY_SYSRQ:
+               if (value == 1 && sysrq_alt) {
+                       sysrq_down = true;
+                       sysrq_alt_use = sysrq_alt;
+               }
+               break;
+
+       default:
+               if (sysrq_down && value && value != 2)
+                       __handle_sysrq(sysrq_xlate[code], true);
+               break;
+       }
+
+out:
+       suppress = sysrq_down;
+       spin_unlock(&sysrq_event_lock);
+
+       return suppress;
+}
+
+static int sysrq_connect(struct input_handler *handler,
+                        struct input_dev *dev,
+                        const struct input_device_id *id)
+{
+       struct input_handle *handle;
+       int error;
+
+       sysrq_down = false;
+       sysrq_alt = 0;
+
+       handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+       if (!handle)
+               return -ENOMEM;
+
+       handle->dev = dev;
+       handle->handler = handler;
+       handle->name = "sysrq";
+
+       error = input_register_handle(handle);
+       if (error) {
+               pr_err("Failed to register input sysrq handler, error %d\n",
+                       error);
+               goto err_free;
+       }
+
+       error = input_open_device(handle);
+       if (error) {
+               pr_err("Failed to open input device, error %d\n", error);
+               goto err_unregister;
+       }
+
+       return 0;
+
+ err_unregister:
+       input_unregister_handle(handle);
+ err_free:
+       kfree(handle);
+       return error;
+}
+
+static void sysrq_disconnect(struct input_handle *handle)
+{
+       input_close_device(handle);
+       input_unregister_handle(handle);
+       kfree(handle);
+}
+
+/*
+ * We are matching on KEY_LEFTALT instead of KEY_SYSRQ because not all
+ * keyboards have SysRq key predefined and so user may add it to keymap
+ * later, but we expect all such keyboards to have left alt.
+ */
+static const struct input_device_id sysrq_ids[] = {
+       {
+               .flags = INPUT_DEVICE_ID_MATCH_EVBIT |
+                               INPUT_DEVICE_ID_MATCH_KEYBIT,
+               .evbit = { BIT_MASK(EV_KEY) },
+               .keybit = { BIT_MASK(KEY_LEFTALT) },
+       },
+       { },
+};
+
+static struct input_handler sysrq_handler = {
+       .filter         = sysrq_filter,
+       .connect        = sysrq_connect,
+       .disconnect     = sysrq_disconnect,
+       .name           = "sysrq",
+       .id_table       = sysrq_ids,
+};
+
+static bool sysrq_handler_registered;
+
+static inline void sysrq_register_handler(void)
+{
+       int error;
+
+       error = input_register_handler(&sysrq_handler);
+       if (error)
+               pr_err("Failed to register input handler, error %d", error);
+       else
+               sysrq_handler_registered = true;
+}
+
+static inline void sysrq_unregister_handler(void)
+{
+       if (sysrq_handler_registered) {
+               input_unregister_handler(&sysrq_handler);
+               sysrq_handler_registered = false;
+       }
+}
+
+#else
+
+static inline void sysrq_register_handler(void)
+{
+}
+
+static inline void sysrq_unregister_handler(void)
+{
+}
+
+#endif /* CONFIG_INPUT */
+
+int sysrq_toggle_support(int enable_mask)
+{
+       bool was_enabled = sysrq_on();
+
+       sysrq_enabled = enable_mask;
+
+       if (was_enabled != sysrq_on()) {
+               if (sysrq_on())
+                       sysrq_register_handler();
+               else
+                       sysrq_unregister_handler();
+       }
+
+       return 0;
+}
+
+static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
+                                struct sysrq_key_op *remove_op_p)
+{
+       int retval;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sysrq_key_table_lock, flags);
+       if (__sysrq_get_key_op(key) == remove_op_p) {
+               __sysrq_put_key_op(key, insert_op_p);
+               retval = 0;
+       } else {
+               retval = -1;
+       }
+       spin_unlock_irqrestore(&sysrq_key_table_lock, flags);
+       return retval;
+}
+
+int register_sysrq_key(int key, struct sysrq_key_op *op_p)
+{
+       return __sysrq_swap_key_ops(key, op_p, NULL);
+}
+EXPORT_SYMBOL(register_sysrq_key);
+
+int unregister_sysrq_key(int key, struct sysrq_key_op *op_p)
+{
+       return __sysrq_swap_key_ops(key, NULL, op_p);
+}
+EXPORT_SYMBOL(unregister_sysrq_key);
+
+#ifdef CONFIG_PROC_FS
+/*
+ * writing 'C' to /proc/sysrq-trigger is like sysrq-C
+ */
+static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
+                                  size_t count, loff_t *ppos)
+{
+       if (count) {
+               char c;
+
+               if (get_user(c, buf))
+                       return -EFAULT;
+               __handle_sysrq(c, false);
+       }
+
+       return count;
+}
+
+static const struct file_operations proc_sysrq_trigger_operations = {
+       .write          = write_sysrq_trigger,
+       .llseek         = noop_llseek,
+};
+
+static void sysrq_init_procfs(void)
+{
+       if (!proc_create("sysrq-trigger", S_IWUSR, NULL,
+                        &proc_sysrq_trigger_operations))
+               pr_err("Failed to register proc interface\n");
+}
+
+#else
+
+static inline void sysrq_init_procfs(void)
+{
+}
+
+#endif /* CONFIG_PROC_FS */
+
+static int __init sysrq_init(void)
+{
+       sysrq_init_procfs();
+
+       if (sysrq_on())
+               sysrq_register_handler();
+
+       return 0;
+}
+module_init(sysrq_init);
diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c
new file mode 100644 (file)
index 0000000..f64582b
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * Creating audit events from TTY input.
+ *
+ * Copyright (C) 2007 Red Hat, Inc.  All rights reserved.  This copyrighted
+ * material is made available to anyone wishing to use, modify, copy, or
+ * redistribute it subject to the terms and conditions of the GNU General
+ * Public License v.2.
+ *
+ * Authors: Miloslav Trmac <mitr@redhat.com>
+ */
+
+#include <linux/audit.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+
+struct tty_audit_buf {
+       atomic_t count;
+       struct mutex mutex;     /* Protects all data below */
+       int major, minor;       /* The TTY which the data is from */
+       unsigned icanon:1;
+       size_t valid;
+       unsigned char *data;    /* Allocated size N_TTY_BUF_SIZE */
+};
+
+static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
+                                                int icanon)
+{
+       struct tty_audit_buf *buf;
+
+       buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+       if (!buf)
+               goto err;
+       buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+       if (!buf->data)
+               goto err_buf;
+       atomic_set(&buf->count, 1);
+       mutex_init(&buf->mutex);
+       buf->major = major;
+       buf->minor = minor;
+       buf->icanon = icanon;
+       buf->valid = 0;
+       return buf;
+
+err_buf:
+       kfree(buf);
+err:
+       return NULL;
+}
+
+static void tty_audit_buf_free(struct tty_audit_buf *buf)
+{
+       WARN_ON(buf->valid != 0);
+       kfree(buf->data);
+       kfree(buf);
+}
+
+static void tty_audit_buf_put(struct tty_audit_buf *buf)
+{
+       if (atomic_dec_and_test(&buf->count))
+               tty_audit_buf_free(buf);
+}
+
+static void tty_audit_log(const char *description, struct task_struct *tsk,
+                         uid_t loginuid, unsigned sessionid, int major,
+                         int minor, unsigned char *data, size_t size)
+{
+       struct audit_buffer *ab;
+
+       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY);
+       if (ab) {
+               char name[sizeof(tsk->comm)];
+               uid_t uid = task_uid(tsk);
+
+               audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u "
+                                "major=%d minor=%d comm=", description,
+                                tsk->pid, uid, loginuid, sessionid,
+                                major, minor);
+               get_task_comm(name, tsk);
+               audit_log_untrustedstring(ab, name);
+               audit_log_format(ab, " data=");
+               audit_log_n_hex(ab, data, size);
+               audit_log_end(ab);
+       }
+}
+
+/**
+ *     tty_audit_buf_push      -       Push buffered data out
+ *
+ *     Generate an audit message from the contents of @buf, which is owned by
+ *     @tsk with @loginuid.  @buf->mutex must be locked.
+ */
+static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
+                              unsigned int sessionid,
+                              struct tty_audit_buf *buf)
+{
+       if (buf->valid == 0)
+               return;
+       if (audit_enabled == 0)
+               return;
+       tty_audit_log("tty", tsk, loginuid, sessionid, buf->major, buf->minor,
+                     buf->data, buf->valid);
+       buf->valid = 0;
+}
+
+/**
+ *     tty_audit_buf_push_current      -       Push buffered data out
+ *
+ *     Generate an audit message from the contents of @buf, which is owned by
+ *     the current task.  @buf->mutex must be locked.
+ */
+static void tty_audit_buf_push_current(struct tty_audit_buf *buf)
+{
+       uid_t auid = audit_get_loginuid(current);
+       unsigned int sessionid = audit_get_sessionid(current);
+       tty_audit_buf_push(current, auid, sessionid, buf);
+}
+
+/**
+ *     tty_audit_exit  -       Handle a task exit
+ *
+ *     Make sure all buffered data is written out and deallocate the buffer.
+ *     Only needs to be called if current->signal->tty_audit_buf != %NULL.
+ */
+void tty_audit_exit(void)
+{
+       struct tty_audit_buf *buf;
+
+       spin_lock_irq(&current->sighand->siglock);
+       buf = current->signal->tty_audit_buf;
+       current->signal->tty_audit_buf = NULL;
+       spin_unlock_irq(&current->sighand->siglock);
+       if (!buf)
+               return;
+
+       mutex_lock(&buf->mutex);
+       tty_audit_buf_push_current(buf);
+       mutex_unlock(&buf->mutex);
+
+       tty_audit_buf_put(buf);
+}
+
+/**
+ *     tty_audit_fork  -       Copy TTY audit state for a new task
+ *
+ *     Set up TTY audit state in @sig from current.  @sig needs no locking.
+ */
+void tty_audit_fork(struct signal_struct *sig)
+{
+       spin_lock_irq(&current->sighand->siglock);
+       sig->audit_tty = current->signal->audit_tty;
+       spin_unlock_irq(&current->sighand->siglock);
+}
+
+/**
+ *     tty_audit_tiocsti       -       Log TIOCSTI
+ */
+void tty_audit_tiocsti(struct tty_struct *tty, char ch)
+{
+       struct tty_audit_buf *buf;
+       int major, minor, should_audit;
+
+       spin_lock_irq(&current->sighand->siglock);
+       should_audit = current->signal->audit_tty;
+       buf = current->signal->tty_audit_buf;
+       if (buf)
+               atomic_inc(&buf->count);
+       spin_unlock_irq(&current->sighand->siglock);
+
+       major = tty->driver->major;
+       minor = tty->driver->minor_start + tty->index;
+       if (buf) {
+               mutex_lock(&buf->mutex);
+               if (buf->major == major && buf->minor == minor)
+                       tty_audit_buf_push_current(buf);
+               mutex_unlock(&buf->mutex);
+               tty_audit_buf_put(buf);
+       }
+
+       if (should_audit && audit_enabled) {
+               uid_t auid;
+               unsigned int sessionid;
+
+               auid = audit_get_loginuid(current);
+               sessionid = audit_get_sessionid(current);
+               tty_audit_log("ioctl=TIOCSTI", current, auid, sessionid, major,
+                             minor, &ch, 1);
+       }
+}
+
+/**
+ * tty_audit_push_task -       Flush task's pending audit data
+ * @tsk:               task pointer
+ * @loginuid:          sender login uid
+ * @sessionid:         sender session id
+ *
+ * Called with a ref on @tsk held. Try to lock sighand and get a
+ * reference to the tty audit buffer if available.
+ * Flush the buffer or return an appropriate error code.
+ */
+int tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid)
+{
+       struct tty_audit_buf *buf = ERR_PTR(-EPERM);
+       unsigned long flags;
+
+       if (!lock_task_sighand(tsk, &flags))
+               return -ESRCH;
+
+       if (tsk->signal->audit_tty) {
+               buf = tsk->signal->tty_audit_buf;
+               if (buf)
+                       atomic_inc(&buf->count);
+       }
+       unlock_task_sighand(tsk, &flags);
+
+       /*
+        * Return 0 when signal->audit_tty set
+        * but tsk->signal->tty_audit_buf == NULL.
+        */
+       if (!buf || IS_ERR(buf))
+               return PTR_ERR(buf);
+
+       mutex_lock(&buf->mutex);
+       tty_audit_buf_push(tsk, loginuid, sessionid, buf);
+       mutex_unlock(&buf->mutex);
+
+       tty_audit_buf_put(buf);
+       return 0;
+}
+
+/**
+ *     tty_audit_buf_get       -       Get an audit buffer.
+ *
+ *     Get an audit buffer for @tty, allocate it if necessary.  Return %NULL
+ *     if TTY auditing is disabled or out of memory.  Otherwise, return a new
+ *     reference to the buffer.
+ */
+static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty)
+{
+       struct tty_audit_buf *buf, *buf2;
+
+       buf = NULL;
+       buf2 = NULL;
+       spin_lock_irq(&current->sighand->siglock);
+       if (likely(!current->signal->audit_tty))
+               goto out;
+       buf = current->signal->tty_audit_buf;
+       if (buf) {
+               atomic_inc(&buf->count);
+               goto out;
+       }
+       spin_unlock_irq(&current->sighand->siglock);
+
+       buf2 = tty_audit_buf_alloc(tty->driver->major,
+                                  tty->driver->minor_start + tty->index,
+                                  tty->icanon);
+       if (buf2 == NULL) {
+               audit_log_lost("out of memory in TTY auditing");
+               return NULL;
+       }
+
+       spin_lock_irq(&current->sighand->siglock);
+       if (!current->signal->audit_tty)
+               goto out;
+       buf = current->signal->tty_audit_buf;
+       if (!buf) {
+               current->signal->tty_audit_buf = buf2;
+               buf = buf2;
+               buf2 = NULL;
+       }
+       atomic_inc(&buf->count);
+       /* Fall through */
+ out:
+       spin_unlock_irq(&current->sighand->siglock);
+       if (buf2)
+               tty_audit_buf_free(buf2);
+       return buf;
+}
+
+/**
+ *     tty_audit_add_data      -       Add data for TTY auditing.
+ *
+ *     Audit @data of @size from @tty, if necessary.
+ */
+void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
+                       size_t size)
+{
+       struct tty_audit_buf *buf;
+       int major, minor;
+
+       if (unlikely(size == 0))
+               return;
+
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY
+           && tty->driver->subtype == PTY_TYPE_MASTER)
+               return;
+
+       buf = tty_audit_buf_get(tty);
+       if (!buf)
+               return;
+
+       mutex_lock(&buf->mutex);
+       major = tty->driver->major;
+       minor = tty->driver->minor_start + tty->index;
+       if (buf->major != major || buf->minor != minor
+           || buf->icanon != tty->icanon) {
+               tty_audit_buf_push_current(buf);
+               buf->major = major;
+               buf->minor = minor;
+               buf->icanon = tty->icanon;
+       }
+       do {
+               size_t run;
+
+               run = N_TTY_BUF_SIZE - buf->valid;
+               if (run > size)
+                       run = size;
+               memcpy(buf->data + buf->valid, data, run);
+               buf->valid += run;
+               data += run;
+               size -= run;
+               if (buf->valid == N_TTY_BUF_SIZE)
+                       tty_audit_buf_push_current(buf);
+       } while (size != 0);
+       mutex_unlock(&buf->mutex);
+       tty_audit_buf_put(buf);
+}
+
+/**
+ *     tty_audit_push  -       Push buffered data out
+ *
+ *     Make sure no audit data is pending for @tty on the current process.
+ */
+void tty_audit_push(struct tty_struct *tty)
+{
+       struct tty_audit_buf *buf;
+
+       spin_lock_irq(&current->sighand->siglock);
+       if (likely(!current->signal->audit_tty)) {
+               spin_unlock_irq(&current->sighand->siglock);
+               return;
+       }
+       buf = current->signal->tty_audit_buf;
+       if (buf)
+               atomic_inc(&buf->count);
+       spin_unlock_irq(&current->sighand->siglock);
+
+       if (buf) {
+               int major, minor;
+
+               major = tty->driver->major;
+               minor = tty->driver->minor_start + tty->index;
+               mutex_lock(&buf->mutex);
+               if (buf->major == major && buf->minor == minor)
+                       tty_audit_buf_push_current(buf);
+               mutex_unlock(&buf->mutex);
+               tty_audit_buf_put(buf);
+       }
+}
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
new file mode 100644 (file)
index 0000000..cc1e985
--- /dev/null
@@ -0,0 +1,524 @@
+/*
+ * Tty buffer allocation management
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+/**
+ *     tty_buffer_free_all             -       free buffers used by a tty
+ *     @tty: tty to free from
+ *
+ *     Remove all the buffers pending on a tty whether queued with data
+ *     or in the free ring. Must be called when the tty is no longer in use
+ *
+ *     Locking: none
+ */
+
+void tty_buffer_free_all(struct tty_struct *tty)
+{
+       struct tty_buffer *thead;
+       while ((thead = tty->buf.head) != NULL) {
+               tty->buf.head = thead->next;
+               kfree(thead);
+       }
+       while ((thead = tty->buf.free) != NULL) {
+               tty->buf.free = thead->next;
+               kfree(thead);
+       }
+       tty->buf.tail = NULL;
+       tty->buf.memory_used = 0;
+}
+
+/**
+ *     tty_buffer_alloc        -       allocate a tty buffer
+ *     @tty: tty device
+ *     @size: desired size (characters)
+ *
+ *     Allocate a new tty buffer to hold the desired number of characters.
+ *     Return NULL if out of memory or the allocation would exceed the
+ *     per device queue
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
+{
+       struct tty_buffer *p;
+
+       if (tty->buf.memory_used + size > 65536)
+               return NULL;
+       p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
+       if (p == NULL)
+               return NULL;
+       p->used = 0;
+       p->size = size;
+       p->next = NULL;
+       p->commit = 0;
+       p->read = 0;
+       p->char_buf_ptr = (char *)(p->data);
+       p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
+       tty->buf.memory_used += size;
+       return p;
+}
+
+/**
+ *     tty_buffer_free         -       free a tty buffer
+ *     @tty: tty owning the buffer
+ *     @b: the buffer to free
+ *
+ *     Free a tty buffer, or add it to the free list according to our
+ *     internal strategy
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
+{
+       /* Dumb strategy for now - should keep some stats */
+       tty->buf.memory_used -= b->size;
+       WARN_ON(tty->buf.memory_used < 0);
+
+       if (b->size >= 512)
+               kfree(b);
+       else {
+               b->next = tty->buf.free;
+               tty->buf.free = b;
+       }
+}
+
+/**
+ *     __tty_buffer_flush              -       flush full tty buffers
+ *     @tty: tty to flush
+ *
+ *     flush all the buffers containing receive data. Caller must
+ *     hold the buffer lock and must have ensured no parallel flush to
+ *     ldisc is running.
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static void __tty_buffer_flush(struct tty_struct *tty)
+{
+       struct tty_buffer *thead;
+
+       while ((thead = tty->buf.head) != NULL) {
+               tty->buf.head = thead->next;
+               tty_buffer_free(tty, thead);
+       }
+       tty->buf.tail = NULL;
+}
+
+/**
+ *     tty_buffer_flush                -       flush full tty buffers
+ *     @tty: tty to flush
+ *
+ *     flush all the buffers containing receive data. If the buffer is
+ *     being processed by flush_to_ldisc then we defer the processing
+ *     to that function
+ *
+ *     Locking: none
+ */
+
+void tty_buffer_flush(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty->buf.lock, flags);
+
+       /* If the data is being pushed to the tty layer then we can't
+          process it here. Instead set a flag and the flush_to_ldisc
+          path will process the flush request before it exits */
+       if (test_bit(TTY_FLUSHING, &tty->flags)) {
+               set_bit(TTY_FLUSHPENDING, &tty->flags);
+               spin_unlock_irqrestore(&tty->buf.lock, flags);
+               wait_event(tty->read_wait,
+                               test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
+               return;
+       } else
+               __tty_buffer_flush(tty);
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+}
+
+/**
+ *     tty_buffer_find         -       find a free tty buffer
+ *     @tty: tty owning the buffer
+ *     @size: characters wanted
+ *
+ *     Locate an existing suitable tty buffer or if we are lacking one then
+ *     allocate a new one. We round our buffers off in 256 character chunks
+ *     to get better allocation behaviour.
+ *
+ *     Locking: Caller must hold tty->buf.lock
+ */
+
+static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
+{
+       struct tty_buffer **tbh = &tty->buf.free;
+       while ((*tbh) != NULL) {
+               struct tty_buffer *t = *tbh;
+               if (t->size >= size) {
+                       *tbh = t->next;
+                       t->next = NULL;
+                       t->used = 0;
+                       t->commit = 0;
+                       t->read = 0;
+                       tty->buf.memory_used += t->size;
+                       return t;
+               }
+               tbh = &((*tbh)->next);
+       }
+       /* Round the buffer size out */
+       size = (size + 0xFF) & ~0xFF;
+       return tty_buffer_alloc(tty, size);
+       /* Should possibly check if this fails for the largest buffer we
+          have queued and recycle that ? */
+}
+
+/**
+ *     tty_buffer_request_room         -       grow tty buffer if needed
+ *     @tty: tty structure
+ *     @size: size desired
+ *
+ *     Make at least size bytes of linear space available for the tty
+ *     buffer. If we fail return the size we managed to find.
+ *
+ *     Locking: Takes tty->buf.lock
+ */
+int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+{
+       struct tty_buffer *b, *n;
+       int left;
+       unsigned long flags;
+
+       spin_lock_irqsave(&tty->buf.lock, flags);
+
+       /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
+          remove this conditional if its worth it. This would be invisible
+          to the callers */
+       if ((b = tty->buf.tail) != NULL)
+               left = b->size - b->used;
+       else
+               left = 0;
+
+       if (left < size) {
+               /* This is the slow path - looking for new buffers to use */
+               if ((n = tty_buffer_find(tty, size)) != NULL) {
+                       if (b != NULL) {
+                               b->next = n;
+                               b->commit = b->used;
+                       } else
+                               tty->buf.head = n;
+                       tty->buf.tail = n;
+               } else
+                       size = left;
+       }
+
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+       return size;
+}
+EXPORT_SYMBOL_GPL(tty_buffer_request_room);
+
+/**
+ *     tty_insert_flip_string_fixed_flag - Add characters to the tty buffer
+ *     @tty: tty structure
+ *     @chars: characters
+ *     @flag: flag value for each character
+ *     @size: size
+ *
+ *     Queue a series of bytes to the tty buffering. All the characters
+ *     passed are marked with the supplied flag. Returns the number added.
+ *
+ *     Locking: Called functions may take tty->buf.lock
+ */
+
+int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
+               const unsigned char *chars, char flag, size_t size)
+{
+       int copied = 0;
+       do {
+               int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
+               int space = tty_buffer_request_room(tty, goal);
+               struct tty_buffer *tb = tty->buf.tail;
+               /* If there is no space then tb may be NULL */
+               if (unlikely(space == 0))
+                       break;
+               memcpy(tb->char_buf_ptr + tb->used, chars, space);
+               memset(tb->flag_buf_ptr + tb->used, flag, space);
+               tb->used += space;
+               copied += space;
+               chars += space;
+               /* There is a small chance that we need to split the data over
+                  several buffers. If this is the case we must loop */
+       } while (unlikely(size > copied));
+       return copied;
+}
+EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag);
+
+/**
+ *     tty_insert_flip_string_flags    -       Add characters to the tty buffer
+ *     @tty: tty structure
+ *     @chars: characters
+ *     @flags: flag bytes
+ *     @size: size
+ *
+ *     Queue a series of bytes to the tty buffering. For each character
+ *     the flags array indicates the status of the character. Returns the
+ *     number added.
+ *
+ *     Locking: Called functions may take tty->buf.lock
+ */
+
+int tty_insert_flip_string_flags(struct tty_struct *tty,
+               const unsigned char *chars, const char *flags, size_t size)
+{
+       int copied = 0;
+       do {
+               int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
+               int space = tty_buffer_request_room(tty, goal);
+               struct tty_buffer *tb = tty->buf.tail;
+               /* If there is no space then tb may be NULL */
+               if (unlikely(space == 0))
+                       break;
+               memcpy(tb->char_buf_ptr + tb->used, chars, space);
+               memcpy(tb->flag_buf_ptr + tb->used, flags, space);
+               tb->used += space;
+               copied += space;
+               chars += space;
+               flags += space;
+               /* There is a small chance that we need to split the data over
+                  several buffers. If this is the case we must loop */
+       } while (unlikely(size > copied));
+       return copied;
+}
+EXPORT_SYMBOL(tty_insert_flip_string_flags);
+
+/**
+ *     tty_schedule_flip       -       push characters to ldisc
+ *     @tty: tty to push from
+ *
+ *     Takes any pending buffers and transfers their ownership to the
+ *     ldisc side of the queue. It then schedules those characters for
+ *     processing by the line discipline.
+ *
+ *     Locking: Takes tty->buf.lock
+ */
+
+void tty_schedule_flip(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty->buf.lock, flags);
+       if (tty->buf.tail != NULL)
+               tty->buf.tail->commit = tty->buf.tail->used;
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+       schedule_delayed_work(&tty->buf.work, 1);
+}
+EXPORT_SYMBOL(tty_schedule_flip);
+
+/**
+ *     tty_prepare_flip_string         -       make room for characters
+ *     @tty: tty
+ *     @chars: return pointer for character write area
+ *     @size: desired size
+ *
+ *     Prepare a block of space in the buffer for data. Returns the length
+ *     available and buffer pointer to the space which is now allocated and
+ *     accounted for as ready for normal characters. This is used for drivers
+ *     that need their own block copy routines into the buffer. There is no
+ *     guarantee the buffer is a DMA target!
+ *
+ *     Locking: May call functions taking tty->buf.lock
+ */
+
+int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
+                                                               size_t size)
+{
+       int space = tty_buffer_request_room(tty, size);
+       if (likely(space)) {
+               struct tty_buffer *tb = tty->buf.tail;
+               *chars = tb->char_buf_ptr + tb->used;
+               memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
+               tb->used += space;
+       }
+       return space;
+}
+EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
+
+/**
+ *     tty_prepare_flip_string_flags   -       make room for characters
+ *     @tty: tty
+ *     @chars: return pointer for character write area
+ *     @flags: return pointer for status flag write area
+ *     @size: desired size
+ *
+ *     Prepare a block of space in the buffer for data. Returns the length
+ *     available and buffer pointer to the space which is now allocated and
+ *     accounted for as ready for characters. This is used for drivers
+ *     that need their own block copy routines into the buffer. There is no
+ *     guarantee the buffer is a DMA target!
+ *
+ *     Locking: May call functions taking tty->buf.lock
+ */
+
+int tty_prepare_flip_string_flags(struct tty_struct *tty,
+                       unsigned char **chars, char **flags, size_t size)
+{
+       int space = tty_buffer_request_room(tty, size);
+       if (likely(space)) {
+               struct tty_buffer *tb = tty->buf.tail;
+               *chars = tb->char_buf_ptr + tb->used;
+               *flags = tb->flag_buf_ptr + tb->used;
+               tb->used += space;
+       }
+       return space;
+}
+EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
+
+
+
+/**
+ *     flush_to_ldisc
+ *     @work: tty structure passed from work queue.
+ *
+ *     This routine is called out of the software interrupt to flush data
+ *     from the buffer chain to the line discipline.
+ *
+ *     Locking: holds tty->buf.lock to guard buffer list. Drops the lock
+ *     while invoking the line discipline receive_buf method. The
+ *     receive_buf method is single threaded for each tty instance.
+ */
+
+static void flush_to_ldisc(struct work_struct *work)
+{
+       struct tty_struct *tty =
+               container_of(work, struct tty_struct, buf.work.work);
+       unsigned long   flags;
+       struct tty_ldisc *disc;
+
+       disc = tty_ldisc_ref(tty);
+       if (disc == NULL)       /*  !TTY_LDISC */
+               return;
+
+       spin_lock_irqsave(&tty->buf.lock, flags);
+
+       if (!test_and_set_bit(TTY_FLUSHING, &tty->flags)) {
+               struct tty_buffer *head;
+               while ((head = tty->buf.head) != NULL) {
+                       int count;
+                       char *char_buf;
+                       unsigned char *flag_buf;
+
+                       count = head->commit - head->read;
+                       if (!count) {
+                               if (head->next == NULL)
+                                       break;
+                               tty->buf.head = head->next;
+                               tty_buffer_free(tty, head);
+                               continue;
+                       }
+                       /* Ldisc or user is trying to flush the buffers
+                          we are feeding to the ldisc, stop feeding the
+                          line discipline as we want to empty the queue */
+                       if (test_bit(TTY_FLUSHPENDING, &tty->flags))
+                               break;
+                       if (!tty->receive_room) {
+                               schedule_delayed_work(&tty->buf.work, 1);
+                               break;
+                       }
+                       if (count > tty->receive_room)
+                               count = tty->receive_room;
+                       char_buf = head->char_buf_ptr + head->read;
+                       flag_buf = head->flag_buf_ptr + head->read;
+                       head->read += count;
+                       spin_unlock_irqrestore(&tty->buf.lock, flags);
+                       disc->ops->receive_buf(tty, char_buf,
+                                                       flag_buf, count);
+                       spin_lock_irqsave(&tty->buf.lock, flags);
+               }
+               clear_bit(TTY_FLUSHING, &tty->flags);
+       }
+
+       /* We may have a deferred request to flush the input buffer,
+          if so pull the chain under the lock and empty the queue */
+       if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
+               __tty_buffer_flush(tty);
+               clear_bit(TTY_FLUSHPENDING, &tty->flags);
+               wake_up(&tty->read_wait);
+       }
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+
+       tty_ldisc_deref(disc);
+}
+
+/**
+ *     tty_flush_to_ldisc
+ *     @tty: tty to push
+ *
+ *     Push the terminal flip buffers to the line discipline.
+ *
+ *     Must not be called from IRQ context.
+ */
+void tty_flush_to_ldisc(struct tty_struct *tty)
+{
+       flush_delayed_work(&tty->buf.work);
+}
+
+/**
+ *     tty_flip_buffer_push    -       terminal
+ *     @tty: tty to push
+ *
+ *     Queue a push of the terminal flip buffers to the line discipline. This
+ *     function must not be called from IRQ context if tty->low_latency is set.
+ *
+ *     In the event of the queue being busy for flipping the work will be
+ *     held off and retried later.
+ *
+ *     Locking: tty buffer lock. Driver locks in low latency mode.
+ */
+
+void tty_flip_buffer_push(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty->buf.lock, flags);
+       if (tty->buf.tail != NULL)
+               tty->buf.tail->commit = tty->buf.tail->used;
+       spin_unlock_irqrestore(&tty->buf.lock, flags);
+
+       if (tty->low_latency)
+               flush_to_ldisc(&tty->buf.work.work);
+       else
+               schedule_delayed_work(&tty->buf.work, 1);
+}
+EXPORT_SYMBOL(tty_flip_buffer_push);
+
+/**
+ *     tty_buffer_init         -       prepare a tty buffer structure
+ *     @tty: tty to initialise
+ *
+ *     Set up the initial state of the buffer management for a tty device.
+ *     Must be called before the other tty buffer functions are used.
+ *
+ *     Locking: none
+ */
+
+void tty_buffer_init(struct tty_struct *tty)
+{
+       spin_lock_init(&tty->buf.lock);
+       tty->buf.head = NULL;
+       tty->buf.tail = NULL;
+       tty->buf.free = NULL;
+       tty->buf.memory_used = 0;
+       INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);
+}
+
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
new file mode 100644 (file)
index 0000000..c05c5af
--- /dev/null
@@ -0,0 +1,3263 @@
+/*
+ *  linux/drivers/char/tty_io.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
+ * or rs-channels. It also implements echoing, cooked mode etc.
+ *
+ * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
+ *
+ * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the
+ * tty_struct and tty_queue structures.  Previously there was an array
+ * of 256 tty_struct's which was statically allocated, and the
+ * tty_queue structures were allocated at boot time.  Both are now
+ * dynamically allocated only when the tty is open.
+ *
+ * Also restructured routines so that there is more of a separation
+ * between the high-level tty routines (tty_io.c and tty_ioctl.c) and
+ * the low-level tty routines (serial.c, pty.c, console.c).  This
+ * makes for cleaner and more compact code.  -TYT, 9/17/92
+ *
+ * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
+ * which can be dynamically activated and de-activated by the line
+ * discipline handling modules (like SLIP).
+ *
+ * NOTE: pay no attention to the line discipline code (yet); its
+ * interface is still subject to change in this version...
+ * -- TYT, 1/31/92
+ *
+ * Added functionality to the OPOST tty handling.  No delays, but all
+ * other bits should be there.
+ *     -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
+ *
+ * Rewrote canonical mode and added more termios flags.
+ *     -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
+ *
+ * Reorganized FASYNC support so mouse code can share it.
+ *     -- ctm@ardi.com, 9Sep95
+ *
+ * New TIOCLINUX variants added.
+ *     -- mj@k332.feld.cvut.cz, 19-Nov-95
+ *
+ * Restrict vt switching via ioctl()
+ *      -- grif@cs.ucr.edu, 5-Dec-95
+ *
+ * Move console and virtual terminal code to more appropriate files,
+ * implement CONFIG_VT and generalize console device interface.
+ *     -- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97
+ *
+ * Rewrote tty_init_dev and tty_release_dev to eliminate races.
+ *     -- Bill Hawes <whawes@star.net>, June 97
+ *
+ * Added devfs support.
+ *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 13-Jan-1998
+ *
+ * Added support for a Unix98-style ptmx device.
+ *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
+ *
+ * Reduced memory usage for older ARM systems
+ *      -- Russell King <rmk@arm.linux.org.uk>
+ *
+ * Move do_SAK() into process context.  Less stack use in devfs functions.
+ * alloc_tty_struct() always uses kmalloc()
+ *                      -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01
+ */
+
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/devpts_fs.h>
+#include <linux/file.h>
+#include <linux/fdtable.h>
+#include <linux/console.h>
+#include <linux/timer.h>
+#include <linux/ctype.h>
+#include <linux/kd.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/smp_lock.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/serial.h>
+
+#include <linux/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+
+#include <linux/kmod.h>
+#include <linux/nsproxy.h>
+
+#undef TTY_DEBUG_HANGUP
+
+#define TTY_PARANOIA_CHECK 1
+#define CHECK_TTY_COUNT 1
+
+struct ktermios tty_std_termios = {    /* for the benefit of tty drivers  */
+       .c_iflag = ICRNL | IXON,
+       .c_oflag = OPOST | ONLCR,
+       .c_cflag = B38400 | CS8 | CREAD | HUPCL,
+       .c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
+                  ECHOCTL | ECHOKE | IEXTEN,
+       .c_cc = INIT_C_CC,
+       .c_ispeed = 38400,
+       .c_ospeed = 38400
+};
+
+EXPORT_SYMBOL(tty_std_termios);
+
+/* This list gets poked at by procfs and various bits of boot up code. This
+   could do with some rationalisation such as pulling the tty proc function
+   into this file */
+
+LIST_HEAD(tty_drivers);                        /* linked list of tty drivers */
+
+/* Mutex to protect creating and releasing a tty. This is shared with
+   vt.c for deeply disgusting hack reasons */
+DEFINE_MUTEX(tty_mutex);
+EXPORT_SYMBOL(tty_mutex);
+
+/* Spinlock to protect the tty->tty_files list */
+DEFINE_SPINLOCK(tty_files_lock);
+
+static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
+static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
+ssize_t redirected_tty_write(struct file *, const char __user *,
+                                                       size_t, loff_t *);
+static unsigned int tty_poll(struct file *, poll_table *);
+static int tty_open(struct inode *, struct file *);
+long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+#ifdef CONFIG_COMPAT
+static long tty_compat_ioctl(struct file *file, unsigned int cmd,
+                               unsigned long arg);
+#else
+#define tty_compat_ioctl NULL
+#endif
+static int __tty_fasync(int fd, struct file *filp, int on);
+static int tty_fasync(int fd, struct file *filp, int on);
+static void release_tty(struct tty_struct *tty, int idx);
+static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
+static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
+
+/**
+ *     alloc_tty_struct        -       allocate a tty object
+ *
+ *     Return a new empty tty structure. The data fields have not
+ *     been initialized in any way but has been zeroed
+ *
+ *     Locking: none
+ */
+
+struct tty_struct *alloc_tty_struct(void)
+{
+       return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
+}
+
+/**
+ *     free_tty_struct         -       free a disused tty
+ *     @tty: tty struct to free
+ *
+ *     Free the write buffers, tty queue and tty memory itself.
+ *
+ *     Locking: none. Must be called after tty is definitely unused
+ */
+
+void free_tty_struct(struct tty_struct *tty)
+{
+       if (tty->dev)
+               put_device(tty->dev);
+       kfree(tty->write_buf);
+       tty_buffer_free_all(tty);
+       kfree(tty);
+}
+
+static inline struct tty_struct *file_tty(struct file *file)
+{
+       return ((struct tty_file_private *)file->private_data)->tty;
+}
+
+/* Associate a new file with the tty structure */
+int tty_add_file(struct tty_struct *tty, struct file *file)
+{
+       struct tty_file_private *priv;
+
+       priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->tty = tty;
+       priv->file = file;
+       file->private_data = priv;
+
+       spin_lock(&tty_files_lock);
+       list_add(&priv->list, &tty->tty_files);
+       spin_unlock(&tty_files_lock);
+
+       return 0;
+}
+
+/* Delete file from its tty */
+void tty_del_file(struct file *file)
+{
+       struct tty_file_private *priv = file->private_data;
+
+       spin_lock(&tty_files_lock);
+       list_del(&priv->list);
+       spin_unlock(&tty_files_lock);
+       file->private_data = NULL;
+       kfree(priv);
+}
+
+
+#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base)
+
+/**
+ *     tty_name        -       return tty naming
+ *     @tty: tty structure
+ *     @buf: buffer for output
+ *
+ *     Convert a tty structure into a name. The name reflects the kernel
+ *     naming policy and if udev is in use may not reflect user space
+ *
+ *     Locking: none
+ */
+
+char *tty_name(struct tty_struct *tty, char *buf)
+{
+       if (!tty) /* Hmm.  NULL pointer.  That's fun. */
+               strcpy(buf, "NULL tty");
+       else
+               strcpy(buf, tty->name);
+       return buf;
+}
+
+EXPORT_SYMBOL(tty_name);
+
+int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
+                             const char *routine)
+{
+#ifdef TTY_PARANOIA_CHECK
+       if (!tty) {
+               printk(KERN_WARNING
+                       "null TTY for (%d:%d) in %s\n",
+                       imajor(inode), iminor(inode), routine);
+               return 1;
+       }
+       if (tty->magic != TTY_MAGIC) {
+               printk(KERN_WARNING
+                       "bad magic number for tty struct (%d:%d) in %s\n",
+                       imajor(inode), iminor(inode), routine);
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+static int check_tty_count(struct tty_struct *tty, const char *routine)
+{
+#ifdef CHECK_TTY_COUNT
+       struct list_head *p;
+       int count = 0;
+
+       spin_lock(&tty_files_lock);
+       list_for_each(p, &tty->tty_files) {
+               count++;
+       }
+       spin_unlock(&tty_files_lock);
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+           tty->driver->subtype == PTY_TYPE_SLAVE &&
+           tty->link && tty->link->count)
+               count++;
+       if (tty->count != count) {
+               printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) "
+                                   "!= #fd's(%d) in %s\n",
+                      tty->name, tty->count, count, routine);
+               return count;
+       }
+#endif
+       return 0;
+}
+
+/**
+ *     get_tty_driver          -       find device of a tty
+ *     @dev_t: device identifier
+ *     @index: returns the index of the tty
+ *
+ *     This routine returns a tty driver structure, given a device number
+ *     and also passes back the index number.
+ *
+ *     Locking: caller must hold tty_mutex
+ */
+
+static struct tty_driver *get_tty_driver(dev_t device, int *index)
+{
+       struct tty_driver *p;
+
+       list_for_each_entry(p, &tty_drivers, tty_drivers) {
+               dev_t base = MKDEV(p->major, p->minor_start);
+               if (device < base || device >= base + p->num)
+                       continue;
+               *index = device - base;
+               return tty_driver_kref_get(p);
+       }
+       return NULL;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+
+/**
+ *     tty_find_polling_driver -       find device of a polled tty
+ *     @name: name string to match
+ *     @line: pointer to resulting tty line nr
+ *
+ *     This routine returns a tty driver structure, given a name
+ *     and the condition that the tty driver is capable of polled
+ *     operation.
+ */
+struct tty_driver *tty_find_polling_driver(char *name, int *line)
+{
+       struct tty_driver *p, *res = NULL;
+       int tty_line = 0;
+       int len;
+       char *str, *stp;
+
+       for (str = name; *str; str++)
+               if ((*str >= '0' && *str <= '9') || *str == ',')
+                       break;
+       if (!*str)
+               return NULL;
+
+       len = str - name;
+       tty_line = simple_strtoul(str, &str, 10);
+
+       mutex_lock(&tty_mutex);
+       /* Search through the tty devices to look for a match */
+       list_for_each_entry(p, &tty_drivers, tty_drivers) {
+               if (strncmp(name, p->name, len) != 0)
+                       continue;
+               stp = str;
+               if (*stp == ',')
+                       stp++;
+               if (*stp == '\0')
+                       stp = NULL;
+
+               if (tty_line >= 0 && tty_line < p->num && p->ops &&
+                   p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) {
+                       res = tty_driver_kref_get(p);
+                       *line = tty_line;
+                       break;
+               }
+       }
+       mutex_unlock(&tty_mutex);
+
+       return res;
+}
+EXPORT_SYMBOL_GPL(tty_find_polling_driver);
+#endif
+
+/**
+ *     tty_check_change        -       check for POSIX terminal changes
+ *     @tty: tty to check
+ *
+ *     If we try to write to, or set the state of, a terminal and we're
+ *     not in the foreground, send a SIGTTOU.  If the signal is blocked or
+ *     ignored, go ahead and perform the operation.  (POSIX 7.2)
+ *
+ *     Locking: ctrl_lock
+ */
+
+int tty_check_change(struct tty_struct *tty)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       if (current->signal->tty != tty)
+               return 0;
+
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+
+       if (!tty->pgrp) {
+               printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n");
+               goto out_unlock;
+       }
+       if (task_pgrp(current) == tty->pgrp)
+               goto out_unlock;
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+       if (is_ignored(SIGTTOU))
+               goto out;
+       if (is_current_pgrp_orphaned()) {
+               ret = -EIO;
+               goto out;
+       }
+       kill_pgrp(task_pgrp(current), SIGTTOU, 1);
+       set_thread_flag(TIF_SIGPENDING);
+       ret = -ERESTARTSYS;
+out:
+       return ret;
+out_unlock:
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+       return ret;
+}
+
+EXPORT_SYMBOL(tty_check_change);
+
+static ssize_t hung_up_tty_read(struct file *file, char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       return 0;
+}
+
+static ssize_t hung_up_tty_write(struct file *file, const char __user *buf,
+                                size_t count, loff_t *ppos)
+{
+       return -EIO;
+}
+
+/* No kernel lock held - none needed ;) */
+static unsigned int hung_up_tty_poll(struct file *filp, poll_table *wait)
+{
+       return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
+}
+
+static long hung_up_tty_ioctl(struct file *file, unsigned int cmd,
+               unsigned long arg)
+{
+       return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
+}
+
+static long hung_up_tty_compat_ioctl(struct file *file,
+                                    unsigned int cmd, unsigned long arg)
+{
+       return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
+}
+
+static const struct file_operations tty_fops = {
+       .llseek         = no_llseek,
+       .read           = tty_read,
+       .write          = tty_write,
+       .poll           = tty_poll,
+       .unlocked_ioctl = tty_ioctl,
+       .compat_ioctl   = tty_compat_ioctl,
+       .open           = tty_open,
+       .release        = tty_release,
+       .fasync         = tty_fasync,
+};
+
+static const struct file_operations console_fops = {
+       .llseek         = no_llseek,
+       .read           = tty_read,
+       .write          = redirected_tty_write,
+       .poll           = tty_poll,
+       .unlocked_ioctl = tty_ioctl,
+       .compat_ioctl   = tty_compat_ioctl,
+       .open           = tty_open,
+       .release        = tty_release,
+       .fasync         = tty_fasync,
+};
+
+static const struct file_operations hung_up_tty_fops = {
+       .llseek         = no_llseek,
+       .read           = hung_up_tty_read,
+       .write          = hung_up_tty_write,
+       .poll           = hung_up_tty_poll,
+       .unlocked_ioctl = hung_up_tty_ioctl,
+       .compat_ioctl   = hung_up_tty_compat_ioctl,
+       .release        = tty_release,
+};
+
+static DEFINE_SPINLOCK(redirect_lock);
+static struct file *redirect;
+
+/**
+ *     tty_wakeup      -       request more data
+ *     @tty: terminal
+ *
+ *     Internal and external helper for wakeups of tty. This function
+ *     informs the line discipline if present that the driver is ready
+ *     to receive more output data.
+ */
+
+void tty_wakeup(struct tty_struct *tty)
+{
+       struct tty_ldisc *ld;
+
+       if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) {
+               ld = tty_ldisc_ref(tty);
+               if (ld) {
+                       if (ld->ops->write_wakeup)
+                               ld->ops->write_wakeup(tty);
+                       tty_ldisc_deref(ld);
+               }
+       }
+       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
+}
+
+EXPORT_SYMBOL_GPL(tty_wakeup);
+
+/**
+ *     __tty_hangup            -       actual handler for hangup events
+ *     @work: tty device
+ *
+ *     This can be called by the "eventd" kernel thread.  That is process
+ *     synchronous but doesn't hold any locks, so we need to make sure we
+ *     have the appropriate locks for what we're doing.
+ *
+ *     The hangup event clears any pending redirections onto the hung up
+ *     device. It ensures future writes will error and it does the needed
+ *     line discipline hangup and signal delivery. The tty object itself
+ *     remains intact.
+ *
+ *     Locking:
+ *             BTM
+ *               redirect lock for undoing redirection
+ *               file list lock for manipulating list of ttys
+ *               tty_ldisc_lock from called functions
+ *               termios_mutex resetting termios data
+ *               tasklist_lock to walk task list for hangup event
+ *                 ->siglock to protect ->signal/->sighand
+ */
+void __tty_hangup(struct tty_struct *tty)
+{
+       struct file *cons_filp = NULL;
+       struct file *filp, *f = NULL;
+       struct task_struct *p;
+       struct tty_file_private *priv;
+       int    closecount = 0, n;
+       unsigned long flags;
+       int refs = 0;
+
+       if (!tty)
+               return;
+
+
+       spin_lock(&redirect_lock);
+       if (redirect && file_tty(redirect) == tty) {
+               f = redirect;
+               redirect = NULL;
+       }
+       spin_unlock(&redirect_lock);
+
+       tty_lock();
+
+       /* inuse_filps is protected by the single tty lock,
+          this really needs to change if we want to flush the
+          workqueue with the lock held */
+       check_tty_count(tty, "tty_hangup");
+
+       spin_lock(&tty_files_lock);
+       /* This breaks for file handles being sent over AF_UNIX sockets ? */
+       list_for_each_entry(priv, &tty->tty_files, list) {
+               filp = priv->file;
+               if (filp->f_op->write == redirected_tty_write)
+                       cons_filp = filp;
+               if (filp->f_op->write != tty_write)
+                       continue;
+               closecount++;
+               __tty_fasync(-1, filp, 0);      /* can't block */
+               filp->f_op = &hung_up_tty_fops;
+       }
+       spin_unlock(&tty_files_lock);
+
+       tty_ldisc_hangup(tty);
+
+       read_lock(&tasklist_lock);
+       if (tty->session) {
+               do_each_pid_task(tty->session, PIDTYPE_SID, p) {
+                       spin_lock_irq(&p->sighand->siglock);
+                       if (p->signal->tty == tty) {
+                               p->signal->tty = NULL;
+                               /* We defer the dereferences outside fo
+                                  the tasklist lock */
+                               refs++;
+                       }
+                       if (!p->signal->leader) {
+                               spin_unlock_irq(&p->sighand->siglock);
+                               continue;
+                       }
+                       __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
+                       __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
+                       put_pid(p->signal->tty_old_pgrp);  /* A noop */
+                       spin_lock_irqsave(&tty->ctrl_lock, flags);
+                       if (tty->pgrp)
+                               p->signal->tty_old_pgrp = get_pid(tty->pgrp);
+                       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+                       spin_unlock_irq(&p->sighand->siglock);
+               } while_each_pid_task(tty->session, PIDTYPE_SID, p);
+       }
+       read_unlock(&tasklist_lock);
+
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       clear_bit(TTY_THROTTLED, &tty->flags);
+       clear_bit(TTY_PUSH, &tty->flags);
+       clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+       put_pid(tty->session);
+       put_pid(tty->pgrp);
+       tty->session = NULL;
+       tty->pgrp = NULL;
+       tty->ctrl_status = 0;
+       set_bit(TTY_HUPPED, &tty->flags);
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+       /* Account for the p->signal references we killed */
+       while (refs--)
+               tty_kref_put(tty);
+
+       /*
+        * If one of the devices matches a console pointer, we
+        * cannot just call hangup() because that will cause
+        * tty->count and state->count to go out of sync.
+        * So we just call close() the right number of times.
+        */
+       if (cons_filp) {
+               if (tty->ops->close)
+                       for (n = 0; n < closecount; n++)
+                               tty->ops->close(tty, cons_filp);
+       } else if (tty->ops->hangup)
+               (tty->ops->hangup)(tty);
+       /*
+        * We don't want to have driver/ldisc interactions beyond
+        * the ones we did here. The driver layer expects no
+        * calls after ->hangup() from the ldisc side. However we
+        * can't yet guarantee all that.
+        */
+       set_bit(TTY_HUPPED, &tty->flags);
+       tty_ldisc_enable(tty);
+
+       tty_unlock();
+
+       if (f)
+               fput(f);
+}
+
+static void do_tty_hangup(struct work_struct *work)
+{
+       struct tty_struct *tty =
+               container_of(work, struct tty_struct, hangup_work);
+
+       __tty_hangup(tty);
+}
+
+/**
+ *     tty_hangup              -       trigger a hangup event
+ *     @tty: tty to hangup
+ *
+ *     A carrier loss (virtual or otherwise) has occurred on this like
+ *     schedule a hangup sequence to run after this event.
+ */
+
+void tty_hangup(struct tty_struct *tty)
+{
+#ifdef TTY_DEBUG_HANGUP
+       char    buf[64];
+       printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf));
+#endif
+       schedule_work(&tty->hangup_work);
+}
+
+EXPORT_SYMBOL(tty_hangup);
+
+/**
+ *     tty_vhangup             -       process vhangup
+ *     @tty: tty to hangup
+ *
+ *     The user has asked via system call for the terminal to be hung up.
+ *     We do this synchronously so that when the syscall returns the process
+ *     is complete. That guarantee is necessary for security reasons.
+ */
+
+void tty_vhangup(struct tty_struct *tty)
+{
+#ifdef TTY_DEBUG_HANGUP
+       char    buf[64];
+
+       printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
+#endif
+       __tty_hangup(tty);
+}
+
+EXPORT_SYMBOL(tty_vhangup);
+
+
+/**
+ *     tty_vhangup_self        -       process vhangup for own ctty
+ *
+ *     Perform a vhangup on the current controlling tty
+ */
+
+void tty_vhangup_self(void)
+{
+       struct tty_struct *tty;
+
+       tty = get_current_tty();
+       if (tty) {
+               tty_vhangup(tty);
+               tty_kref_put(tty);
+       }
+}
+
+/**
+ *     tty_hung_up_p           -       was tty hung up
+ *     @filp: file pointer of tty
+ *
+ *     Return true if the tty has been subject to a vhangup or a carrier
+ *     loss
+ */
+
+int tty_hung_up_p(struct file *filp)
+{
+       return (filp->f_op == &hung_up_tty_fops);
+}
+
+EXPORT_SYMBOL(tty_hung_up_p);
+
+static void session_clear_tty(struct pid *session)
+{
+       struct task_struct *p;
+       do_each_pid_task(session, PIDTYPE_SID, p) {
+               proc_clear_tty(p);
+       } while_each_pid_task(session, PIDTYPE_SID, p);
+}
+
+/**
+ *     disassociate_ctty       -       disconnect controlling tty
+ *     @on_exit: true if exiting so need to "hang up" the session
+ *
+ *     This function is typically called only by the session leader, when
+ *     it wants to disassociate itself from its controlling tty.
+ *
+ *     It performs the following functions:
+ *     (1)  Sends a SIGHUP and SIGCONT to the foreground process group
+ *     (2)  Clears the tty from being controlling the session
+ *     (3)  Clears the controlling tty for all processes in the
+ *             session group.
+ *
+ *     The argument on_exit is set to 1 if called when a process is
+ *     exiting; it is 0 if called by the ioctl TIOCNOTTY.
+ *
+ *     Locking:
+ *             BTM is taken for hysterical raisins, and held when
+ *               called from no_tty().
+ *               tty_mutex is taken to protect tty
+ *               ->siglock is taken to protect ->signal/->sighand
+ *               tasklist_lock is taken to walk process list for sessions
+ *                 ->siglock is taken to protect ->signal/->sighand
+ */
+
+void disassociate_ctty(int on_exit)
+{
+       struct tty_struct *tty;
+       struct pid *tty_pgrp = NULL;
+
+       if (!current->signal->leader)
+               return;
+
+       tty = get_current_tty();
+       if (tty) {
+               tty_pgrp = get_pid(tty->pgrp);
+               if (on_exit) {
+                       if (tty->driver->type != TTY_DRIVER_TYPE_PTY)
+                               tty_vhangup(tty);
+               }
+               tty_kref_put(tty);
+       } else if (on_exit) {
+               struct pid *old_pgrp;
+               spin_lock_irq(&current->sighand->siglock);
+               old_pgrp = current->signal->tty_old_pgrp;
+               current->signal->tty_old_pgrp = NULL;
+               spin_unlock_irq(&current->sighand->siglock);
+               if (old_pgrp) {
+                       kill_pgrp(old_pgrp, SIGHUP, on_exit);
+                       kill_pgrp(old_pgrp, SIGCONT, on_exit);
+                       put_pid(old_pgrp);
+               }
+               return;
+       }
+       if (tty_pgrp) {
+               kill_pgrp(tty_pgrp, SIGHUP, on_exit);
+               if (!on_exit)
+                       kill_pgrp(tty_pgrp, SIGCONT, on_exit);
+               put_pid(tty_pgrp);
+       }
+
+       spin_lock_irq(&current->sighand->siglock);
+       put_pid(current->signal->tty_old_pgrp);
+       current->signal->tty_old_pgrp = NULL;
+       spin_unlock_irq(&current->sighand->siglock);
+
+       tty = get_current_tty();
+       if (tty) {
+               unsigned long flags;
+               spin_lock_irqsave(&tty->ctrl_lock, flags);
+               put_pid(tty->session);
+               put_pid(tty->pgrp);
+               tty->session = NULL;
+               tty->pgrp = NULL;
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               tty_kref_put(tty);
+       } else {
+#ifdef TTY_DEBUG_HANGUP
+               printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
+                      " = NULL", tty);
+#endif
+       }
+
+       /* Now clear signal->tty under the lock */
+       read_lock(&tasklist_lock);
+       session_clear_tty(task_session(current));
+       read_unlock(&tasklist_lock);
+}
+
+/**
+ *
+ *     no_tty  - Ensure the current process does not have a controlling tty
+ */
+void no_tty(void)
+{
+       struct task_struct *tsk = current;
+       tty_lock();
+       disassociate_ctty(0);
+       tty_unlock();
+       proc_clear_tty(tsk);
+}
+
+
+/**
+ *     stop_tty        -       propagate flow control
+ *     @tty: tty to stop
+ *
+ *     Perform flow control to the driver. For PTY/TTY pairs we
+ *     must also propagate the TIOCKPKT status. May be called
+ *     on an already stopped device and will not re-call the driver
+ *     method.
+ *
+ *     This functionality is used by both the line disciplines for
+ *     halting incoming flow and by the driver. It may therefore be
+ *     called from any context, may be under the tty atomic_write_lock
+ *     but not always.
+ *
+ *     Locking:
+ *             Uses the tty control lock internally
+ */
+
+void stop_tty(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       if (tty->stopped) {
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               return;
+       }
+       tty->stopped = 1;
+       if (tty->link && tty->link->packet) {
+               tty->ctrl_status &= ~TIOCPKT_START;
+               tty->ctrl_status |= TIOCPKT_STOP;
+               wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
+       }
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+       if (tty->ops->stop)
+               (tty->ops->stop)(tty);
+}
+
+EXPORT_SYMBOL(stop_tty);
+
+/**
+ *     start_tty       -       propagate flow control
+ *     @tty: tty to start
+ *
+ *     Start a tty that has been stopped if at all possible. Perform
+ *     any necessary wakeups and propagate the TIOCPKT status. If this
+ *     is the tty was previous stopped and is being started then the
+ *     driver start method is invoked and the line discipline woken.
+ *
+ *     Locking:
+ *             ctrl_lock
+ */
+
+void start_tty(struct tty_struct *tty)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       if (!tty->stopped || tty->flow_stopped) {
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               return;
+       }
+       tty->stopped = 0;
+       if (tty->link && tty->link->packet) {
+               tty->ctrl_status &= ~TIOCPKT_STOP;
+               tty->ctrl_status |= TIOCPKT_START;
+               wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
+       }
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+       if (tty->ops->start)
+               (tty->ops->start)(tty);
+       /* If we have a running line discipline it may need kicking */
+       tty_wakeup(tty);
+}
+
+EXPORT_SYMBOL(start_tty);
+
+/**
+ *     tty_read        -       read method for tty device files
+ *     @file: pointer to tty file
+ *     @buf: user buffer
+ *     @count: size of user buffer
+ *     @ppos: unused
+ *
+ *     Perform the read system call function on this terminal device. Checks
+ *     for hung up devices before calling the line discipline method.
+ *
+ *     Locking:
+ *             Locks the line discipline internally while needed. Multiple
+ *     read calls may be outstanding in parallel.
+ */
+
+static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
+                       loff_t *ppos)
+{
+       int i;
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct tty_struct *tty = file_tty(file);
+       struct tty_ldisc *ld;
+
+       if (tty_paranoia_check(tty, inode, "tty_read"))
+               return -EIO;
+       if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
+               return -EIO;
+
+       /* We want to wait for the line discipline to sort out in this
+          situation */
+       ld = tty_ldisc_ref_wait(tty);
+       if (ld->ops->read)
+               i = (ld->ops->read)(tty, file, buf, count);
+       else
+               i = -EIO;
+       tty_ldisc_deref(ld);
+       if (i > 0)
+               inode->i_atime = current_fs_time(inode->i_sb);
+       return i;
+}
+
+void tty_write_unlock(struct tty_struct *tty)
+{
+       mutex_unlock(&tty->atomic_write_lock);
+       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
+}
+
+int tty_write_lock(struct tty_struct *tty, int ndelay)
+{
+       if (!mutex_trylock(&tty->atomic_write_lock)) {
+               if (ndelay)
+                       return -EAGAIN;
+               if (mutex_lock_interruptible(&tty->atomic_write_lock))
+                       return -ERESTARTSYS;
+       }
+       return 0;
+}
+
+/*
+ * Split writes up in sane blocksizes to avoid
+ * denial-of-service type attacks
+ */
+static inline ssize_t do_tty_write(
+       ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),
+       struct tty_struct *tty,
+       struct file *file,
+       const char __user *buf,
+       size_t count)
+{
+       ssize_t ret, written = 0;
+       unsigned int chunk;
+
+       ret = tty_write_lock(tty, file->f_flags & O_NDELAY);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * We chunk up writes into a temporary buffer. This
+        * simplifies low-level drivers immensely, since they
+        * don't have locking issues and user mode accesses.
+        *
+        * But if TTY_NO_WRITE_SPLIT is set, we should use a
+        * big chunk-size..
+        *
+        * The default chunk-size is 2kB, because the NTTY
+        * layer has problems with bigger chunks. It will
+        * claim to be able to handle more characters than
+        * it actually does.
+        *
+        * FIXME: This can probably go away now except that 64K chunks
+        * are too likely to fail unless switched to vmalloc...
+        */
+       chunk = 2048;
+       if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags))
+               chunk = 65536;
+       if (count < chunk)
+               chunk = count;
+
+       /* write_buf/write_cnt is protected by the atomic_write_lock mutex */
+       if (tty->write_cnt < chunk) {
+               unsigned char *buf_chunk;
+
+               if (chunk < 1024)
+                       chunk = 1024;
+
+               buf_chunk = kmalloc(chunk, GFP_KERNEL);
+               if (!buf_chunk) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               kfree(tty->write_buf);
+               tty->write_cnt = chunk;
+               tty->write_buf = buf_chunk;
+       }
+
+       /* Do the write .. */
+       for (;;) {
+               size_t size = count;
+               if (size > chunk)
+                       size = chunk;
+               ret = -EFAULT;
+               if (copy_from_user(tty->write_buf, buf, size))
+                       break;
+               ret = write(tty, file, tty->write_buf, size);
+               if (ret <= 0)
+                       break;
+               written += ret;
+               buf += ret;
+               count -= ret;
+               if (!count)
+                       break;
+               ret = -ERESTARTSYS;
+               if (signal_pending(current))
+                       break;
+               cond_resched();
+       }
+       if (written) {
+               struct inode *inode = file->f_path.dentry->d_inode;
+               inode->i_mtime = current_fs_time(inode->i_sb);
+               ret = written;
+       }
+out:
+       tty_write_unlock(tty);
+       return ret;
+}
+
+/**
+ * tty_write_message - write a message to a certain tty, not just the console.
+ * @tty: the destination tty_struct
+ * @msg: the message to write
+ *
+ * This is used for messages that need to be redirected to a specific tty.
+ * We don't put it into the syslog queue right now maybe in the future if
+ * really needed.
+ *
+ * We must still hold the BTM and test the CLOSING flag for the moment.
+ */
+
+void tty_write_message(struct tty_struct *tty, char *msg)
+{
+       if (tty) {
+               mutex_lock(&tty->atomic_write_lock);
+               tty_lock();
+               if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
+                       tty_unlock();
+                       tty->ops->write(tty, msg, strlen(msg));
+               } else
+                       tty_unlock();
+               tty_write_unlock(tty);
+       }
+       return;
+}
+
+
+/**
+ *     tty_write               -       write method for tty device file
+ *     @file: tty file pointer
+ *     @buf: user data to write
+ *     @count: bytes to write
+ *     @ppos: unused
+ *
+ *     Write data to a tty device via the line discipline.
+ *
+ *     Locking:
+ *             Locks the line discipline as required
+ *             Writes to the tty driver are serialized by the atomic_write_lock
+ *     and are then processed in chunks to the device. The line discipline
+ *     write method will not be invoked in parallel for each device.
+ */
+
+static ssize_t tty_write(struct file *file, const char __user *buf,
+                                               size_t count, loff_t *ppos)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct tty_struct *tty = file_tty(file);
+       struct tty_ldisc *ld;
+       ssize_t ret;
+
+       if (tty_paranoia_check(tty, inode, "tty_write"))
+               return -EIO;
+       if (!tty || !tty->ops->write ||
+               (test_bit(TTY_IO_ERROR, &tty->flags)))
+                       return -EIO;
+       /* Short term debug to catch buggy drivers */
+       if (tty->ops->write_room == NULL)
+               printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
+                       tty->driver->name);
+       ld = tty_ldisc_ref_wait(tty);
+       if (!ld->ops->write)
+               ret = -EIO;
+       else
+               ret = do_tty_write(ld->ops->write, tty, file, buf, count);
+       tty_ldisc_deref(ld);
+       return ret;
+}
+
+ssize_t redirected_tty_write(struct file *file, const char __user *buf,
+                                               size_t count, loff_t *ppos)
+{
+       struct file *p = NULL;
+
+       spin_lock(&redirect_lock);
+       if (redirect) {
+               get_file(redirect);
+               p = redirect;
+       }
+       spin_unlock(&redirect_lock);
+
+       if (p) {
+               ssize_t res;
+               res = vfs_write(p, buf, count, &p->f_pos);
+               fput(p);
+               return res;
+       }
+       return tty_write(file, buf, count, ppos);
+}
+
+static char ptychar[] = "pqrstuvwxyzabcde";
+
+/**
+ *     pty_line_name   -       generate name for a pty
+ *     @driver: the tty driver in use
+ *     @index: the minor number
+ *     @p: output buffer of at least 6 bytes
+ *
+ *     Generate a name from a driver reference and write it to the output
+ *     buffer.
+ *
+ *     Locking: None
+ */
+static void pty_line_name(struct tty_driver *driver, int index, char *p)
+{
+       int i = index + driver->name_base;
+       /* ->name is initialized to "ttyp", but "tty" is expected */
+       sprintf(p, "%s%c%x",
+               driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name,
+               ptychar[i >> 4 & 0xf], i & 0xf);
+}
+
+/**
+ *     tty_line_name   -       generate name for a tty
+ *     @driver: the tty driver in use
+ *     @index: the minor number
+ *     @p: output buffer of at least 7 bytes
+ *
+ *     Generate a name from a driver reference and write it to the output
+ *     buffer.
+ *
+ *     Locking: None
+ */
+static void tty_line_name(struct tty_driver *driver, int index, char *p)
+{
+       sprintf(p, "%s%d", driver->name, index + driver->name_base);
+}
+
+/**
+ *     tty_driver_lookup_tty() - find an existing tty, if any
+ *     @driver: the driver for the tty
+ *     @idx:    the minor number
+ *
+ *     Return the tty, if found or ERR_PTR() otherwise.
+ *
+ *     Locking: tty_mutex must be held. If tty is found, the mutex must
+ *     be held until the 'fast-open' is also done. Will change once we
+ *     have refcounting in the driver and per driver locking
+ */
+static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
+               struct inode *inode, int idx)
+{
+       struct tty_struct *tty;
+
+       if (driver->ops->lookup)
+               return driver->ops->lookup(driver, inode, idx);
+
+       tty = driver->ttys[idx];
+       return tty;
+}
+
+/**
+ *     tty_init_termios        -  helper for termios setup
+ *     @tty: the tty to set up
+ *
+ *     Initialise the termios structures for this tty. Thus runs under
+ *     the tty_mutex currently so we can be relaxed about ordering.
+ */
+
+int tty_init_termios(struct tty_struct *tty)
+{
+       struct ktermios *tp;
+       int idx = tty->index;
+
+       tp = tty->driver->termios[idx];
+       if (tp == NULL) {
+               tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
+               if (tp == NULL)
+                       return -ENOMEM;
+               memcpy(tp, &tty->driver->init_termios,
+                                               sizeof(struct ktermios));
+               tty->driver->termios[idx] = tp;
+       }
+       tty->termios = tp;
+       tty->termios_locked = tp + 1;
+
+       /* Compatibility until drivers always set this */
+       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
+       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tty_init_termios);
+
+/**
+ *     tty_driver_install_tty() - install a tty entry in the driver
+ *     @driver: the driver for the tty
+ *     @tty: the tty
+ *
+ *     Install a tty object into the driver tables. The tty->index field
+ *     will be set by the time this is called. This method is responsible
+ *     for ensuring any need additional structures are allocated and
+ *     configured.
+ *
+ *     Locking: tty_mutex for now
+ */
+static int tty_driver_install_tty(struct tty_driver *driver,
+                                               struct tty_struct *tty)
+{
+       int idx = tty->index;
+       int ret;
+
+       if (driver->ops->install) {
+               ret = driver->ops->install(driver, tty);
+               return ret;
+       }
+
+       if (tty_init_termios(tty) == 0) {
+               tty_driver_kref_get(driver);
+               tty->count++;
+               driver->ttys[idx] = tty;
+               return 0;
+       }
+       return -ENOMEM;
+}
+
+/**
+ *     tty_driver_remove_tty() - remove a tty from the driver tables
+ *     @driver: the driver for the tty
+ *     @idx:    the minor number
+ *
+ *     Remvoe a tty object from the driver tables. The tty->index field
+ *     will be set by the time this is called.
+ *
+ *     Locking: tty_mutex for now
+ */
+static void tty_driver_remove_tty(struct tty_driver *driver,
+                                               struct tty_struct *tty)
+{
+       if (driver->ops->remove)
+               driver->ops->remove(driver, tty);
+       else
+               driver->ttys[tty->index] = NULL;
+}
+
+/*
+ *     tty_reopen()    - fast re-open of an open tty
+ *     @tty    - the tty to open
+ *
+ *     Return 0 on success, -errno on error.
+ *
+ *     Locking: tty_mutex must be held from the time the tty was found
+ *              till this open completes.
+ */
+static int tty_reopen(struct tty_struct *tty)
+{
+       struct tty_driver *driver = tty->driver;
+
+       if (test_bit(TTY_CLOSING, &tty->flags))
+               return -EIO;
+
+       if (driver->type == TTY_DRIVER_TYPE_PTY &&
+           driver->subtype == PTY_TYPE_MASTER) {
+               /*
+                * special case for PTY masters: only one open permitted,
+                * and the slave side open count is incremented as well.
+                */
+               if (tty->count)
+                       return -EIO;
+
+               tty->link->count++;
+       }
+       tty->count++;
+       tty->driver = driver; /* N.B. why do this every time?? */
+
+       mutex_lock(&tty->ldisc_mutex);
+       WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
+       mutex_unlock(&tty->ldisc_mutex);
+
+       return 0;
+}
+
+/**
+ *     tty_init_dev            -       initialise a tty device
+ *     @driver: tty driver we are opening a device on
+ *     @idx: device index
+ *     @ret_tty: returned tty structure
+ *     @first_ok: ok to open a new device (used by ptmx)
+ *
+ *     Prepare a tty device. This may not be a "new" clean device but
+ *     could also be an active device. The pty drivers require special
+ *     handling because of this.
+ *
+ *     Locking:
+ *             The function is called under the tty_mutex, which
+ *     protects us from the tty struct or driver itself going away.
+ *
+ *     On exit the tty device has the line discipline attached and
+ *     a reference count of 1. If a pair was created for pty/tty use
+ *     and the other was a pty master then it too has a reference count of 1.
+ *
+ * WSH 06/09/97: Rewritten to remove races and properly clean up after a
+ * failed open.  The new code protects the open with a mutex, so it's
+ * really quite straightforward.  The mutex locking can probably be
+ * relaxed for the (most common) case of reopening a tty.
+ */
+
+struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
+                                                               int first_ok)
+{
+       struct tty_struct *tty;
+       int retval;
+
+       /* Check if pty master is being opened multiple times */
+       if (driver->subtype == PTY_TYPE_MASTER &&
+               (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
+               return ERR_PTR(-EIO);
+       }
+
+       /*
+        * First time open is complex, especially for PTY devices.
+        * This code guarantees that either everything succeeds and the
+        * TTY is ready for operation, or else the table slots are vacated
+        * and the allocated memory released.  (Except that the termios
+        * and locked termios may be retained.)
+        */
+
+       if (!try_module_get(driver->owner))
+               return ERR_PTR(-ENODEV);
+
+       tty = alloc_tty_struct();
+       if (!tty)
+               goto fail_no_mem;
+       initialize_tty_struct(tty, driver, idx);
+
+       retval = tty_driver_install_tty(driver, tty);
+       if (retval < 0) {
+               free_tty_struct(tty);
+               module_put(driver->owner);
+               return ERR_PTR(retval);
+       }
+
+       /*
+        * Structures all installed ... call the ldisc open routines.
+        * If we fail here just call release_tty to clean up.  No need
+        * to decrement the use counts, as release_tty doesn't care.
+        */
+       retval = tty_ldisc_setup(tty, tty->link);
+       if (retval)
+               goto release_mem_out;
+       return tty;
+
+fail_no_mem:
+       module_put(driver->owner);
+       return ERR_PTR(-ENOMEM);
+
+       /* call the tty release_tty routine to clean out this slot */
+release_mem_out:
+       if (printk_ratelimit())
+               printk(KERN_INFO "tty_init_dev: ldisc open failed, "
+                                "clearing slot %d\n", idx);
+       release_tty(tty, idx);
+       return ERR_PTR(retval);
+}
+
+void tty_free_termios(struct tty_struct *tty)
+{
+       struct ktermios *tp;
+       int idx = tty->index;
+       /* Kill this flag and push into drivers for locking etc */
+       if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
+               /* FIXME: Locking on ->termios array */
+               tp = tty->termios;
+               tty->driver->termios[idx] = NULL;
+               kfree(tp);
+       }
+}
+EXPORT_SYMBOL(tty_free_termios);
+
+void tty_shutdown(struct tty_struct *tty)
+{
+       tty_driver_remove_tty(tty->driver, tty);
+       tty_free_termios(tty);
+}
+EXPORT_SYMBOL(tty_shutdown);
+
+/**
+ *     release_one_tty         -       release tty structure memory
+ *     @kref: kref of tty we are obliterating
+ *
+ *     Releases memory associated with a tty structure, and clears out the
+ *     driver table slots. This function is called when a device is no longer
+ *     in use. It also gets called when setup of a device fails.
+ *
+ *     Locking:
+ *             tty_mutex - sometimes only
+ *             takes the file list lock internally when working on the list
+ *     of ttys that the driver keeps.
+ *
+ *     This method gets called from a work queue so that the driver private
+ *     cleanup ops can sleep (needed for USB at least)
+ */
+static void release_one_tty(struct work_struct *work)
+{
+       struct tty_struct *tty =
+               container_of(work, struct tty_struct, hangup_work);
+       struct tty_driver *driver = tty->driver;
+
+       if (tty->ops->cleanup)
+               tty->ops->cleanup(tty);
+
+       tty->magic = 0;
+       tty_driver_kref_put(driver);
+       module_put(driver->owner);
+
+       spin_lock(&tty_files_lock);
+       list_del_init(&tty->tty_files);
+       spin_unlock(&tty_files_lock);
+
+       put_pid(tty->pgrp);
+       put_pid(tty->session);
+       free_tty_struct(tty);
+}
+
+static void queue_release_one_tty(struct kref *kref)
+{
+       struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
+
+       if (tty->ops->shutdown)
+               tty->ops->shutdown(tty);
+       else
+               tty_shutdown(tty);
+
+       /* The hangup queue is now free so we can reuse it rather than
+          waste a chunk of memory for each port */
+       INIT_WORK(&tty->hangup_work, release_one_tty);
+       schedule_work(&tty->hangup_work);
+}
+
+/**
+ *     tty_kref_put            -       release a tty kref
+ *     @tty: tty device
+ *
+ *     Release a reference to a tty device and if need be let the kref
+ *     layer destruct the object for us
+ */
+
+void tty_kref_put(struct tty_struct *tty)
+{
+       if (tty)
+               kref_put(&tty->kref, queue_release_one_tty);
+}
+EXPORT_SYMBOL(tty_kref_put);
+
+/**
+ *     release_tty             -       release tty structure memory
+ *
+ *     Release both @tty and a possible linked partner (think pty pair),
+ *     and decrement the refcount of the backing module.
+ *
+ *     Locking:
+ *             tty_mutex - sometimes only
+ *             takes the file list lock internally when working on the list
+ *     of ttys that the driver keeps.
+ *             FIXME: should we require tty_mutex is held here ??
+ *
+ */
+static void release_tty(struct tty_struct *tty, int idx)
+{
+       /* This should always be true but check for the moment */
+       WARN_ON(tty->index != idx);
+
+       if (tty->link)
+               tty_kref_put(tty->link);
+       tty_kref_put(tty);
+}
+
+/**
+ *     tty_release             -       vfs callback for close
+ *     @inode: inode of tty
+ *     @filp: file pointer for handle to tty
+ *
+ *     Called the last time each file handle is closed that references
+ *     this tty. There may however be several such references.
+ *
+ *     Locking:
+ *             Takes bkl. See tty_release_dev
+ *
+ * Even releasing the tty structures is a tricky business.. We have
+ * to be very careful that the structures are all released at the
+ * same time, as interrupts might otherwise get the wrong pointers.
+ *
+ * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
+ * lead to double frees or releasing memory still in use.
+ */
+
+int tty_release(struct inode *inode, struct file *filp)
+{
+       struct tty_struct *tty = file_tty(filp);
+       struct tty_struct *o_tty;
+       int     pty_master, tty_closing, o_tty_closing, do_sleep;
+       int     devpts;
+       int     idx;
+       char    buf[64];
+
+       if (tty_paranoia_check(tty, inode, "tty_release_dev"))
+               return 0;
+
+       tty_lock();
+       check_tty_count(tty, "tty_release_dev");
+
+       __tty_fasync(-1, filp, 0);
+
+       idx = tty->index;
+       pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+                     tty->driver->subtype == PTY_TYPE_MASTER);
+       devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
+       o_tty = tty->link;
+
+#ifdef TTY_PARANOIA_CHECK
+       if (idx < 0 || idx >= tty->driver->num) {
+               printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
+                                 "free (%s)\n", tty->name);
+               tty_unlock();
+               return 0;
+       }
+       if (!devpts) {
+               if (tty != tty->driver->ttys[idx]) {
+                       tty_unlock();
+                       printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
+                              "for (%s)\n", idx, tty->name);
+                       return 0;
+               }
+               if (tty->termios != tty->driver->termios[idx]) {
+                       tty_unlock();
+                       printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
+                              "for (%s)\n",
+                              idx, tty->name);
+                       return 0;
+               }
+       }
+#endif
+
+#ifdef TTY_DEBUG_HANGUP
+       printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...",
+              tty_name(tty, buf), tty->count);
+#endif
+
+#ifdef TTY_PARANOIA_CHECK
+       if (tty->driver->other &&
+            !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
+               if (o_tty != tty->driver->other->ttys[idx]) {
+                       tty_unlock();
+                       printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
+                                         "not o_tty for (%s)\n",
+                              idx, tty->name);
+                       return 0 ;
+               }
+               if (o_tty->termios != tty->driver->other->termios[idx]) {
+                       tty_unlock();
+                       printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
+                                         "not o_termios for (%s)\n",
+                              idx, tty->name);
+                       return 0;
+               }
+               if (o_tty->link != tty) {
+                       tty_unlock();
+                       printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
+                       return 0;
+               }
+       }
+#endif
+       if (tty->ops->close)
+               tty->ops->close(tty, filp);
+
+       tty_unlock();
+       /*
+        * Sanity check: if tty->count is going to zero, there shouldn't be
+        * any waiters on tty->read_wait or tty->write_wait.  We test the
+        * wait queues and kick everyone out _before_ actually starting to
+        * close.  This ensures that we won't block while releasing the tty
+        * structure.
+        *
+        * The test for the o_tty closing is necessary, since the master and
+        * slave sides may close in any order.  If the slave side closes out
+        * first, its count will be one, since the master side holds an open.
+        * Thus this test wouldn't be triggered at the time the slave closes,
+        * so we do it now.
+        *
+        * Note that it's possible for the tty to be opened again while we're
+        * flushing out waiters.  By recalculating the closing flags before
+        * each iteration we avoid any problems.
+        */
+       while (1) {
+               /* Guard against races with tty->count changes elsewhere and
+                  opens on /dev/tty */
+
+               mutex_lock(&tty_mutex);
+               tty_lock();
+               tty_closing = tty->count <= 1;
+               o_tty_closing = o_tty &&
+                       (o_tty->count <= (pty_master ? 1 : 0));
+               do_sleep = 0;
+
+               if (tty_closing) {
+                       if (waitqueue_active(&tty->read_wait)) {
+                               wake_up_poll(&tty->read_wait, POLLIN);
+                               do_sleep++;
+                       }
+                       if (waitqueue_active(&tty->write_wait)) {
+                               wake_up_poll(&tty->write_wait, POLLOUT);
+                               do_sleep++;
+                       }
+               }
+               if (o_tty_closing) {
+                       if (waitqueue_active(&o_tty->read_wait)) {
+                               wake_up_poll(&o_tty->read_wait, POLLIN);
+                               do_sleep++;
+                       }
+                       if (waitqueue_active(&o_tty->write_wait)) {
+                               wake_up_poll(&o_tty->write_wait, POLLOUT);
+                               do_sleep++;
+                       }
+               }
+               if (!do_sleep)
+                       break;
+
+               printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
+                                   "active!\n", tty_name(tty, buf));
+               tty_unlock();
+               mutex_unlock(&tty_mutex);
+               schedule();
+       }
+
+       /*
+        * The closing flags are now consistent with the open counts on
+        * both sides, and we've completed the last operation that could
+        * block, so it's safe to proceed with closing.
+        */
+       if (pty_master) {
+               if (--o_tty->count < 0) {
+                       printk(KERN_WARNING "tty_release_dev: bad pty slave count "
+                                           "(%d) for %s\n",
+                              o_tty->count, tty_name(o_tty, buf));
+                       o_tty->count = 0;
+               }
+       }
+       if (--tty->count < 0) {
+               printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n",
+                      tty->count, tty_name(tty, buf));
+               tty->count = 0;
+       }
+
+       /*
+        * We've decremented tty->count, so we need to remove this file
+        * descriptor off the tty->tty_files list; this serves two
+        * purposes:
+        *  - check_tty_count sees the correct number of file descriptors
+        *    associated with this tty.
+        *  - do_tty_hangup no longer sees this file descriptor as
+        *    something that needs to be handled for hangups.
+        */
+       tty_del_file(filp);
+
+       /*
+        * Perform some housekeeping before deciding whether to return.
+        *
+        * Set the TTY_CLOSING flag if this was the last open.  In the
+        * case of a pty we may have to wait around for the other side
+        * to close, and TTY_CLOSING makes sure we can't be reopened.
+        */
+       if (tty_closing)
+               set_bit(TTY_CLOSING, &tty->flags);
+       if (o_tty_closing)
+               set_bit(TTY_CLOSING, &o_tty->flags);
+
+       /*
+        * If _either_ side is closing, make sure there aren't any
+        * processes that still think tty or o_tty is their controlling
+        * tty.
+        */
+       if (tty_closing || o_tty_closing) {
+               read_lock(&tasklist_lock);
+               session_clear_tty(tty->session);
+               if (o_tty)
+                       session_clear_tty(o_tty->session);
+               read_unlock(&tasklist_lock);
+       }
+
+       mutex_unlock(&tty_mutex);
+
+       /* check whether both sides are closing ... */
+       if (!tty_closing || (o_tty && !o_tty_closing)) {
+               tty_unlock();
+               return 0;
+       }
+
+#ifdef TTY_DEBUG_HANGUP
+       printk(KERN_DEBUG "freeing tty structure...");
+#endif
+       /*
+        * Ask the line discipline code to release its structures
+        */
+       tty_ldisc_release(tty, o_tty);
+       /*
+        * The release_tty function takes care of the details of clearing
+        * the slots and preserving the termios structure.
+        */
+       release_tty(tty, idx);
+
+       /* Make this pty number available for reallocation */
+       if (devpts)
+               devpts_kill_index(inode, idx);
+       tty_unlock();
+       return 0;
+}
+
+/**
+ *     tty_open                -       open a tty device
+ *     @inode: inode of device file
+ *     @filp: file pointer to tty
+ *
+ *     tty_open and tty_release keep up the tty count that contains the
+ *     number of opens done on a tty. We cannot use the inode-count, as
+ *     different inodes might point to the same tty.
+ *
+ *     Open-counting is needed for pty masters, as well as for keeping
+ *     track of serial lines: DTR is dropped when the last close happens.
+ *     (This is not done solely through tty->count, now.  - Ted 1/27/92)
+ *
+ *     The termios state of a pty is reset on first open so that
+ *     settings don't persist across reuse.
+ *
+ *     Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work.
+ *              tty->count should protect the rest.
+ *              ->siglock protects ->signal/->sighand
+ */
+
+static int tty_open(struct inode *inode, struct file *filp)
+{
+       struct tty_struct *tty = NULL;
+       int noctty, retval;
+       struct tty_driver *driver;
+       int index;
+       dev_t device = inode->i_rdev;
+       unsigned saved_flags = filp->f_flags;
+
+       nonseekable_open(inode, filp);
+
+retry_open:
+       noctty = filp->f_flags & O_NOCTTY;
+       index  = -1;
+       retval = 0;
+
+       mutex_lock(&tty_mutex);
+       tty_lock();
+
+       if (device == MKDEV(TTYAUX_MAJOR, 0)) {
+               tty = get_current_tty();
+               if (!tty) {
+                       tty_unlock();
+                       mutex_unlock(&tty_mutex);
+                       return -ENXIO;
+               }
+               driver = tty_driver_kref_get(tty->driver);
+               index = tty->index;
+               filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
+               /* noctty = 1; */
+               /* FIXME: Should we take a driver reference ? */
+               tty_kref_put(tty);
+               goto got_driver;
+       }
+#ifdef CONFIG_VT
+       if (device == MKDEV(TTY_MAJOR, 0)) {
+               extern struct tty_driver *console_driver;
+               driver = tty_driver_kref_get(console_driver);
+               index = fg_console;
+               noctty = 1;
+               goto got_driver;
+       }
+#endif
+       if (device == MKDEV(TTYAUX_MAJOR, 1)) {
+               struct tty_driver *console_driver = console_device(&index);
+               if (console_driver) {
+                       driver = tty_driver_kref_get(console_driver);
+                       if (driver) {
+                               /* Don't let /dev/console block */
+                               filp->f_flags |= O_NONBLOCK;
+                               noctty = 1;
+                               goto got_driver;
+                       }
+               }
+               tty_unlock();
+               mutex_unlock(&tty_mutex);
+               return -ENODEV;
+       }
+
+       driver = get_tty_driver(device, &index);
+       if (!driver) {
+               tty_unlock();
+               mutex_unlock(&tty_mutex);
+               return -ENODEV;
+       }
+got_driver:
+       if (!tty) {
+               /* check whether we're reopening an existing tty */
+               tty = tty_driver_lookup_tty(driver, inode, index);
+
+               if (IS_ERR(tty)) {
+                       tty_unlock();
+                       mutex_unlock(&tty_mutex);
+                       return PTR_ERR(tty);
+               }
+       }
+
+       if (tty) {
+               retval = tty_reopen(tty);
+               if (retval)
+                       tty = ERR_PTR(retval);
+       } else
+               tty = tty_init_dev(driver, index, 0);
+
+       mutex_unlock(&tty_mutex);
+       tty_driver_kref_put(driver);
+       if (IS_ERR(tty)) {
+               tty_unlock();
+               return PTR_ERR(tty);
+       }
+
+       retval = tty_add_file(tty, filp);
+       if (retval) {
+               tty_unlock();
+               return retval;
+       }
+
+       check_tty_count(tty, "tty_open");
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+           tty->driver->subtype == PTY_TYPE_MASTER)
+               noctty = 1;
+#ifdef TTY_DEBUG_HANGUP
+       printk(KERN_DEBUG "opening %s...", tty->name);
+#endif
+       if (!retval) {
+               if (tty->ops->open)
+                       retval = tty->ops->open(tty, filp);
+               else
+                       retval = -ENODEV;
+       }
+       filp->f_flags = saved_flags;
+
+       if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) &&
+                                               !capable(CAP_SYS_ADMIN))
+               retval = -EBUSY;
+
+       if (retval) {
+#ifdef TTY_DEBUG_HANGUP
+               printk(KERN_DEBUG "error %d in opening %s...", retval,
+                      tty->name);
+#endif
+               tty_unlock(); /* need to call tty_release without BTM */
+               tty_release(inode, filp);
+               if (retval != -ERESTARTSYS)
+                       return retval;
+
+               if (signal_pending(current))
+                       return retval;
+
+               schedule();
+               /*
+                * Need to reset f_op in case a hangup happened.
+                */
+               tty_lock();
+               if (filp->f_op == &hung_up_tty_fops)
+                       filp->f_op = &tty_fops;
+               tty_unlock();
+               goto retry_open;
+       }
+       tty_unlock();
+
+
+       mutex_lock(&tty_mutex);
+       tty_lock();
+       spin_lock_irq(&current->sighand->siglock);
+       if (!noctty &&
+           current->signal->leader &&
+           !current->signal->tty &&
+           tty->session == NULL)
+               __proc_set_tty(current, tty);
+       spin_unlock_irq(&current->sighand->siglock);
+       tty_unlock();
+       mutex_unlock(&tty_mutex);
+       return 0;
+}
+
+
+
+/**
+ *     tty_poll        -       check tty status
+ *     @filp: file being polled
+ *     @wait: poll wait structures to update
+ *
+ *     Call the line discipline polling method to obtain the poll
+ *     status of the device.
+ *
+ *     Locking: locks called line discipline but ldisc poll method
+ *     may be re-entered freely by other callers.
+ */
+
+static unsigned int tty_poll(struct file *filp, poll_table *wait)
+{
+       struct tty_struct *tty = file_tty(filp);
+       struct tty_ldisc *ld;
+       int ret = 0;
+
+       if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_poll"))
+               return 0;
+
+       ld = tty_ldisc_ref_wait(tty);
+       if (ld->ops->poll)
+               ret = (ld->ops->poll)(tty, filp, wait);
+       tty_ldisc_deref(ld);
+       return ret;
+}
+
+static int __tty_fasync(int fd, struct file *filp, int on)
+{
+       struct tty_struct *tty = file_tty(filp);
+       unsigned long flags;
+       int retval = 0;
+
+       if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync"))
+               goto out;
+
+       retval = fasync_helper(fd, filp, on, &tty->fasync);
+       if (retval <= 0)
+               goto out;
+
+       if (on) {
+               enum pid_type type;
+               struct pid *pid;
+               if (!waitqueue_active(&tty->read_wait))
+                       tty->minimum_to_wake = 1;
+               spin_lock_irqsave(&tty->ctrl_lock, flags);
+               if (tty->pgrp) {
+                       pid = tty->pgrp;
+                       type = PIDTYPE_PGID;
+               } else {
+                       pid = task_pid(current);
+                       type = PIDTYPE_PID;
+               }
+               get_pid(pid);
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               retval = __f_setown(filp, pid, type, 0);
+               put_pid(pid);
+               if (retval)
+                       goto out;
+       } else {
+               if (!tty->fasync && !waitqueue_active(&tty->read_wait))
+                       tty->minimum_to_wake = N_TTY_BUF_SIZE;
+       }
+       retval = 0;
+out:
+       return retval;
+}
+
+static int tty_fasync(int fd, struct file *filp, int on)
+{
+       int retval;
+       tty_lock();
+       retval = __tty_fasync(fd, filp, on);
+       tty_unlock();
+       return retval;
+}
+
+/**
+ *     tiocsti                 -       fake input character
+ *     @tty: tty to fake input into
+ *     @p: pointer to character
+ *
+ *     Fake input to a tty device. Does the necessary locking and
+ *     input management.
+ *
+ *     FIXME: does not honour flow control ??
+ *
+ *     Locking:
+ *             Called functions take tty_ldisc_lock
+ *             current->signal->tty check is safe without locks
+ *
+ *     FIXME: may race normal receive processing
+ */
+
+static int tiocsti(struct tty_struct *tty, char __user *p)
+{
+       char ch, mbz = 0;
+       struct tty_ldisc *ld;
+
+       if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       if (get_user(ch, p))
+               return -EFAULT;
+       tty_audit_tiocsti(tty, ch);
+       ld = tty_ldisc_ref_wait(tty);
+       ld->ops->receive_buf(tty, &ch, &mbz, 1);
+       tty_ldisc_deref(ld);
+       return 0;
+}
+
+/**
+ *     tiocgwinsz              -       implement window query ioctl
+ *     @tty; tty
+ *     @arg: user buffer for result
+ *
+ *     Copies the kernel idea of the window size into the user buffer.
+ *
+ *     Locking: tty->termios_mutex is taken to ensure the winsize data
+ *             is consistent.
+ */
+
+static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
+{
+       int err;
+
+       mutex_lock(&tty->termios_mutex);
+       err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
+       mutex_unlock(&tty->termios_mutex);
+
+       return err ? -EFAULT: 0;
+}
+
+/**
+ *     tty_do_resize           -       resize event
+ *     @tty: tty being resized
+ *     @rows: rows (character)
+ *     @cols: cols (character)
+ *
+ *     Update the termios variables and send the necessary signals to
+ *     peform a terminal resize correctly
+ */
+
+int tty_do_resize(struct tty_struct *tty, struct winsize *ws)
+{
+       struct pid *pgrp;
+       unsigned long flags;
+
+       /* Lock the tty */
+       mutex_lock(&tty->termios_mutex);
+       if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
+               goto done;
+       /* Get the PID values and reference them so we can
+          avoid holding the tty ctrl lock while sending signals */
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       pgrp = get_pid(tty->pgrp);
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+       if (pgrp)
+               kill_pgrp(pgrp, SIGWINCH, 1);
+       put_pid(pgrp);
+
+       tty->winsize = *ws;
+done:
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
+}
+
+/**
+ *     tiocswinsz              -       implement window size set ioctl
+ *     @tty; tty side of tty
+ *     @arg: user buffer for result
+ *
+ *     Copies the user idea of the window size to the kernel. Traditionally
+ *     this is just advisory information but for the Linux console it
+ *     actually has driver level meaning and triggers a VC resize.
+ *
+ *     Locking:
+ *             Driver dependant. The default do_resize method takes the
+ *     tty termios mutex and ctrl_lock. The console takes its own lock
+ *     then calls into the default method.
+ */
+
+static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg)
+{
+       struct winsize tmp_ws;
+       if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
+               return -EFAULT;
+
+       if (tty->ops->resize)
+               return tty->ops->resize(tty, &tmp_ws);
+       else
+               return tty_do_resize(tty, &tmp_ws);
+}
+
+/**
+ *     tioccons        -       allow admin to move logical console
+ *     @file: the file to become console
+ *
+ *     Allow the adminstrator to move the redirected console device
+ *
+ *     Locking: uses redirect_lock to guard the redirect information
+ */
+
+static int tioccons(struct file *file)
+{
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       if (file->f_op->write == redirected_tty_write) {
+               struct file *f;
+               spin_lock(&redirect_lock);
+               f = redirect;
+               redirect = NULL;
+               spin_unlock(&redirect_lock);
+               if (f)
+                       fput(f);
+               return 0;
+       }
+       spin_lock(&redirect_lock);
+       if (redirect) {
+               spin_unlock(&redirect_lock);
+               return -EBUSY;
+       }
+       get_file(file);
+       redirect = file;
+       spin_unlock(&redirect_lock);
+       return 0;
+}
+
+/**
+ *     fionbio         -       non blocking ioctl
+ *     @file: file to set blocking value
+ *     @p: user parameter
+ *
+ *     Historical tty interfaces had a blocking control ioctl before
+ *     the generic functionality existed. This piece of history is preserved
+ *     in the expected tty API of posix OS's.
+ *
+ *     Locking: none, the open file handle ensures it won't go away.
+ */
+
+static int fionbio(struct file *file, int __user *p)
+{
+       int nonblock;
+
+       if (get_user(nonblock, p))
+               return -EFAULT;
+
+       spin_lock(&file->f_lock);
+       if (nonblock)
+               file->f_flags |= O_NONBLOCK;
+       else
+               file->f_flags &= ~O_NONBLOCK;
+       spin_unlock(&file->f_lock);
+       return 0;
+}
+
+/**
+ *     tiocsctty       -       set controlling tty
+ *     @tty: tty structure
+ *     @arg: user argument
+ *
+ *     This ioctl is used to manage job control. It permits a session
+ *     leader to set this tty as the controlling tty for the session.
+ *
+ *     Locking:
+ *             Takes tty_mutex() to protect tty instance
+ *             Takes tasklist_lock internally to walk sessions
+ *             Takes ->siglock() when updating signal->tty
+ */
+
+static int tiocsctty(struct tty_struct *tty, int arg)
+{
+       int ret = 0;
+       if (current->signal->leader && (task_session(current) == tty->session))
+               return ret;
+
+       mutex_lock(&tty_mutex);
+       /*
+        * The process must be a session leader and
+        * not have a controlling tty already.
+        */
+       if (!current->signal->leader || current->signal->tty) {
+               ret = -EPERM;
+               goto unlock;
+       }
+
+       if (tty->session) {
+               /*
+                * This tty is already the controlling
+                * tty for another session group!
+                */
+               if (arg == 1 && capable(CAP_SYS_ADMIN)) {
+                       /*
+                        * Steal it away
+                        */
+                       read_lock(&tasklist_lock);
+                       session_clear_tty(tty->session);
+                       read_unlock(&tasklist_lock);
+               } else {
+                       ret = -EPERM;
+                       goto unlock;
+               }
+       }
+       proc_set_tty(current, tty);
+unlock:
+       mutex_unlock(&tty_mutex);
+       return ret;
+}
+
+/**
+ *     tty_get_pgrp    -       return a ref counted pgrp pid
+ *     @tty: tty to read
+ *
+ *     Returns a refcounted instance of the pid struct for the process
+ *     group controlling the tty.
+ */
+
+struct pid *tty_get_pgrp(struct tty_struct *tty)
+{
+       unsigned long flags;
+       struct pid *pgrp;
+
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       pgrp = get_pid(tty->pgrp);
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+       return pgrp;
+}
+EXPORT_SYMBOL_GPL(tty_get_pgrp);
+
+/**
+ *     tiocgpgrp               -       get process group
+ *     @tty: tty passed by user
+ *     @real_tty: tty side of the tty pased by the user if a pty else the tty
+ *     @p: returned pid
+ *
+ *     Obtain the process group of the tty. If there is no process group
+ *     return an error.
+ *
+ *     Locking: none. Reference to current->signal->tty is safe.
+ */
+
+static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
+{
+       struct pid *pid;
+       int ret;
+       /*
+        * (tty == real_tty) is a cheap way of
+        * testing if the tty is NOT a master pty.
+        */
+       if (tty == real_tty && current->signal->tty != real_tty)
+               return -ENOTTY;
+       pid = tty_get_pgrp(real_tty);
+       ret =  put_user(pid_vnr(pid), p);
+       put_pid(pid);
+       return ret;
+}
+
+/**
+ *     tiocspgrp               -       attempt to set process group
+ *     @tty: tty passed by user
+ *     @real_tty: tty side device matching tty passed by user
+ *     @p: pid pointer
+ *
+ *     Set the process group of the tty to the session passed. Only
+ *     permitted where the tty session is our session.
+ *
+ *     Locking: RCU, ctrl lock
+ */
+
+static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
+{
+       struct pid *pgrp;
+       pid_t pgrp_nr;
+       int retval = tty_check_change(real_tty);
+       unsigned long flags;
+
+       if (retval == -EIO)
+               return -ENOTTY;
+       if (retval)
+               return retval;
+       if (!current->signal->tty ||
+           (current->signal->tty != real_tty) ||
+           (real_tty->session != task_session(current)))
+               return -ENOTTY;
+       if (get_user(pgrp_nr, p))
+               return -EFAULT;
+       if (pgrp_nr < 0)
+               return -EINVAL;
+       rcu_read_lock();
+       pgrp = find_vpid(pgrp_nr);
+       retval = -ESRCH;
+       if (!pgrp)
+               goto out_unlock;
+       retval = -EPERM;
+       if (session_of_pgrp(pgrp) != task_session(current))
+               goto out_unlock;
+       retval = 0;
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       put_pid(real_tty->pgrp);
+       real_tty->pgrp = get_pid(pgrp);
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+out_unlock:
+       rcu_read_unlock();
+       return retval;
+}
+
+/**
+ *     tiocgsid                -       get session id
+ *     @tty: tty passed by user
+ *     @real_tty: tty side of the tty pased by the user if a pty else the tty
+ *     @p: pointer to returned session id
+ *
+ *     Obtain the session id of the tty. If there is no session
+ *     return an error.
+ *
+ *     Locking: none. Reference to current->signal->tty is safe.
+ */
+
+static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
+{
+       /*
+        * (tty == real_tty) is a cheap way of
+        * testing if the tty is NOT a master pty.
+       */
+       if (tty == real_tty && current->signal->tty != real_tty)
+               return -ENOTTY;
+       if (!real_tty->session)
+               return -ENOTTY;
+       return put_user(pid_vnr(real_tty->session), p);
+}
+
+/**
+ *     tiocsetd        -       set line discipline
+ *     @tty: tty device
+ *     @p: pointer to user data
+ *
+ *     Set the line discipline according to user request.
+ *
+ *     Locking: see tty_set_ldisc, this function is just a helper
+ */
+
+static int tiocsetd(struct tty_struct *tty, int __user *p)
+{
+       int ldisc;
+       int ret;
+
+       if (get_user(ldisc, p))
+               return -EFAULT;
+
+       ret = tty_set_ldisc(tty, ldisc);
+
+       return ret;
+}
+
+/**
+ *     send_break      -       performed time break
+ *     @tty: device to break on
+ *     @duration: timeout in mS
+ *
+ *     Perform a timed break on hardware that lacks its own driver level
+ *     timed break functionality.
+ *
+ *     Locking:
+ *             atomic_write_lock serializes
+ *
+ */
+
+static int send_break(struct tty_struct *tty, unsigned int duration)
+{
+       int retval;
+
+       if (tty->ops->break_ctl == NULL)
+               return 0;
+
+       if (tty->driver->flags & TTY_DRIVER_HARDWARE_BREAK)
+               retval = tty->ops->break_ctl(tty, duration);
+       else {
+               /* Do the work ourselves */
+               if (tty_write_lock(tty, 0) < 0)
+                       return -EINTR;
+               retval = tty->ops->break_ctl(tty, -1);
+               if (retval)
+                       goto out;
+               if (!signal_pending(current))
+                       msleep_interruptible(duration);
+               retval = tty->ops->break_ctl(tty, 0);
+out:
+               tty_write_unlock(tty);
+               if (signal_pending(current))
+                       retval = -EINTR;
+       }
+       return retval;
+}
+
+/**
+ *     tty_tiocmget            -       get modem status
+ *     @tty: tty device
+ *     @file: user file pointer
+ *     @p: pointer to result
+ *
+ *     Obtain the modem status bits from the tty driver if the feature
+ *     is supported. Return -EINVAL if it is not available.
+ *
+ *     Locking: none (up to the driver)
+ */
+
+static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p)
+{
+       int retval = -EINVAL;
+
+       if (tty->ops->tiocmget) {
+               retval = tty->ops->tiocmget(tty, file);
+
+               if (retval >= 0)
+                       retval = put_user(retval, p);
+       }
+       return retval;
+}
+
+/**
+ *     tty_tiocmset            -       set modem status
+ *     @tty: tty device
+ *     @file: user file pointer
+ *     @cmd: command - clear bits, set bits or set all
+ *     @p: pointer to desired bits
+ *
+ *     Set the modem status bits from the tty driver if the feature
+ *     is supported. Return -EINVAL if it is not available.
+ *
+ *     Locking: none (up to the driver)
+ */
+
+static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd,
+            unsigned __user *p)
+{
+       int retval;
+       unsigned int set, clear, val;
+
+       if (tty->ops->tiocmset == NULL)
+               return -EINVAL;
+
+       retval = get_user(val, p);
+       if (retval)
+               return retval;
+       set = clear = 0;
+       switch (cmd) {
+       case TIOCMBIS:
+               set = val;
+               break;
+       case TIOCMBIC:
+               clear = val;
+               break;
+       case TIOCMSET:
+               set = val;
+               clear = ~val;
+               break;
+       }
+       set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
+       clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
+       return tty->ops->tiocmset(tty, file, set, clear);
+}
+
+static int tty_tiocgicount(struct tty_struct *tty, void __user *arg)
+{
+       int retval = -EINVAL;
+       struct serial_icounter_struct icount;
+       memset(&icount, 0, sizeof(icount));
+       if (tty->ops->get_icount)
+               retval = tty->ops->get_icount(tty, &icount);
+       if (retval != 0)
+               return retval;
+       if (copy_to_user(arg, &icount, sizeof(icount)))
+               return -EFAULT;
+       return 0;
+}
+
+struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
+{
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+           tty->driver->subtype == PTY_TYPE_MASTER)
+               tty = tty->link;
+       return tty;
+}
+EXPORT_SYMBOL(tty_pair_get_tty);
+
+struct tty_struct *tty_pair_get_pty(struct tty_struct *tty)
+{
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+           tty->driver->subtype == PTY_TYPE_MASTER)
+           return tty;
+       return tty->link;
+}
+EXPORT_SYMBOL(tty_pair_get_pty);
+
+/*
+ * Split this up, as gcc can choke on it otherwise..
+ */
+long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct tty_struct *tty = file_tty(file);
+       struct tty_struct *real_tty;
+       void __user *p = (void __user *)arg;
+       int retval;
+       struct tty_ldisc *ld;
+       struct inode *inode = file->f_dentry->d_inode;
+
+       if (tty_paranoia_check(tty, inode, "tty_ioctl"))
+               return -EINVAL;
+
+       real_tty = tty_pair_get_tty(tty);
+
+       /*
+        * Factor out some common prep work
+        */
+       switch (cmd) {
+       case TIOCSETD:
+       case TIOCSBRK:
+       case TIOCCBRK:
+       case TCSBRK:
+       case TCSBRKP:
+               retval = tty_check_change(tty);
+               if (retval)
+                       return retval;
+               if (cmd != TIOCCBRK) {
+                       tty_wait_until_sent(tty, 0);
+                       if (signal_pending(current))
+                               return -EINTR;
+               }
+               break;
+       }
+
+       /*
+        *      Now do the stuff.
+        */
+       switch (cmd) {
+       case TIOCSTI:
+               return tiocsti(tty, p);
+       case TIOCGWINSZ:
+               return tiocgwinsz(real_tty, p);
+       case TIOCSWINSZ:
+               return tiocswinsz(real_tty, p);
+       case TIOCCONS:
+               return real_tty != tty ? -EINVAL : tioccons(file);
+       case FIONBIO:
+               return fionbio(file, p);
+       case TIOCEXCL:
+               set_bit(TTY_EXCLUSIVE, &tty->flags);
+               return 0;
+       case TIOCNXCL:
+               clear_bit(TTY_EXCLUSIVE, &tty->flags);
+               return 0;
+       case TIOCNOTTY:
+               if (current->signal->tty != tty)
+                       return -ENOTTY;
+               no_tty();
+               return 0;
+       case TIOCSCTTY:
+               return tiocsctty(tty, arg);
+       case TIOCGPGRP:
+               return tiocgpgrp(tty, real_tty, p);
+       case TIOCSPGRP:
+               return tiocspgrp(tty, real_tty, p);
+       case TIOCGSID:
+               return tiocgsid(tty, real_tty, p);
+       case TIOCGETD:
+               return put_user(tty->ldisc->ops->num, (int __user *)p);
+       case TIOCSETD:
+               return tiocsetd(tty, p);
+       /*
+        * Break handling
+        */
+       case TIOCSBRK:  /* Turn break on, unconditionally */
+               if (tty->ops->break_ctl)
+                       return tty->ops->break_ctl(tty, -1);
+               return 0;
+       case TIOCCBRK:  /* Turn break off, unconditionally */
+               if (tty->ops->break_ctl)
+                       return tty->ops->break_ctl(tty, 0);
+               return 0;
+       case TCSBRK:   /* SVID version: non-zero arg --> no break */
+               /* non-zero arg means wait for all output data
+                * to be sent (performed above) but don't send break.
+                * This is used by the tcdrain() termios function.
+                */
+               if (!arg)
+                       return send_break(tty, 250);
+               return 0;
+       case TCSBRKP:   /* support for POSIX tcsendbreak() */
+               return send_break(tty, arg ? arg*100 : 250);
+
+       case TIOCMGET:
+               return tty_tiocmget(tty, file, p);
+       case TIOCMSET:
+       case TIOCMBIC:
+       case TIOCMBIS:
+               return tty_tiocmset(tty, file, cmd, p);
+       case TIOCGICOUNT:
+               retval = tty_tiocgicount(tty, p);
+               /* For the moment allow fall through to the old method */
+               if (retval != -EINVAL)
+                       return retval;
+               break;
+       case TCFLSH:
+               switch (arg) {
+               case TCIFLUSH:
+               case TCIOFLUSH:
+               /* flush tty buffer and allow ldisc to process ioctl */
+                       tty_buffer_flush(tty);
+                       break;
+               }
+               break;
+       }
+       if (tty->ops->ioctl) {
+               retval = (tty->ops->ioctl)(tty, file, cmd, arg);
+               if (retval != -ENOIOCTLCMD)
+                       return retval;
+       }
+       ld = tty_ldisc_ref_wait(tty);
+       retval = -EINVAL;
+       if (ld->ops->ioctl) {
+               retval = ld->ops->ioctl(tty, file, cmd, arg);
+               if (retval == -ENOIOCTLCMD)
+                       retval = -EINVAL;
+       }
+       tty_ldisc_deref(ld);
+       return retval;
+}
+
+#ifdef CONFIG_COMPAT
+static long tty_compat_ioctl(struct file *file, unsigned int cmd,
+                               unsigned long arg)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct tty_struct *tty = file_tty(file);
+       struct tty_ldisc *ld;
+       int retval = -ENOIOCTLCMD;
+
+       if (tty_paranoia_check(tty, inode, "tty_ioctl"))
+               return -EINVAL;
+
+       if (tty->ops->compat_ioctl) {
+               retval = (tty->ops->compat_ioctl)(tty, file, cmd, arg);
+               if (retval != -ENOIOCTLCMD)
+                       return retval;
+       }
+
+       ld = tty_ldisc_ref_wait(tty);
+       if (ld->ops->compat_ioctl)
+               retval = ld->ops->compat_ioctl(tty, file, cmd, arg);
+       tty_ldisc_deref(ld);
+
+       return retval;
+}
+#endif
+
+/*
+ * This implements the "Secure Attention Key" ---  the idea is to
+ * prevent trojan horses by killing all processes associated with this
+ * tty when the user hits the "Secure Attention Key".  Required for
+ * super-paranoid applications --- see the Orange Book for more details.
+ *
+ * This code could be nicer; ideally it should send a HUP, wait a few
+ * seconds, then send a INT, and then a KILL signal.  But you then
+ * have to coordinate with the init process, since all processes associated
+ * with the current tty must be dead before the new getty is allowed
+ * to spawn.
+ *
+ * Now, if it would be correct ;-/ The current code has a nasty hole -
+ * it doesn't catch files in flight. We may send the descriptor to ourselves
+ * via AF_UNIX socket, close it and later fetch from socket. FIXME.
+ *
+ * Nasty bug: do_SAK is being called in interrupt context.  This can
+ * deadlock.  We punt it up to process context.  AKPM - 16Mar2001
+ */
+void __do_SAK(struct tty_struct *tty)
+{
+#ifdef TTY_SOFT_SAK
+       tty_hangup(tty);
+#else
+       struct task_struct *g, *p;
+       struct pid *session;
+       int             i;
+       struct file     *filp;
+       struct fdtable *fdt;
+
+       if (!tty)
+               return;
+       session = tty->session;
+
+       tty_ldisc_flush(tty);
+
+       tty_driver_flush_buffer(tty);
+
+       read_lock(&tasklist_lock);
+       /* Kill the entire session */
+       do_each_pid_task(session, PIDTYPE_SID, p) {
+               printk(KERN_NOTICE "SAK: killed process %d"
+                       " (%s): task_session(p)==tty->session\n",
+                       task_pid_nr(p), p->comm);
+               send_sig(SIGKILL, p, 1);
+       } while_each_pid_task(session, PIDTYPE_SID, p);
+       /* Now kill any processes that happen to have the
+        * tty open.
+        */
+       do_each_thread(g, p) {
+               if (p->signal->tty == tty) {
+                       printk(KERN_NOTICE "SAK: killed process %d"
+                           " (%s): task_session(p)==tty->session\n",
+                           task_pid_nr(p), p->comm);
+                       send_sig(SIGKILL, p, 1);
+                       continue;
+               }
+               task_lock(p);
+               if (p->files) {
+                       /*
+                        * We don't take a ref to the file, so we must
+                        * hold ->file_lock instead.
+                        */
+                       spin_lock(&p->files->file_lock);
+                       fdt = files_fdtable(p->files);
+                       for (i = 0; i < fdt->max_fds; i++) {
+                               filp = fcheck_files(p->files, i);
+                               if (!filp)
+                                       continue;
+                               if (filp->f_op->read == tty_read &&
+                                   file_tty(filp) == tty) {
+                                       printk(KERN_NOTICE "SAK: killed process %d"
+                                           " (%s): fd#%d opened to the tty\n",
+                                           task_pid_nr(p), p->comm, i);
+                                       force_sig(SIGKILL, p);
+                                       break;
+                               }
+                       }
+                       spin_unlock(&p->files->file_lock);
+               }
+               task_unlock(p);
+       } while_each_thread(g, p);
+       read_unlock(&tasklist_lock);
+#endif
+}
+
+static void do_SAK_work(struct work_struct *work)
+{
+       struct tty_struct *tty =
+               container_of(work, struct tty_struct, SAK_work);
+       __do_SAK(tty);
+}
+
+/*
+ * The tq handling here is a little racy - tty->SAK_work may already be queued.
+ * Fortunately we don't need to worry, because if ->SAK_work is already queued,
+ * the values which we write to it will be identical to the values which it
+ * already has. --akpm
+ */
+void do_SAK(struct tty_struct *tty)
+{
+       if (!tty)
+               return;
+       schedule_work(&tty->SAK_work);
+}
+
+EXPORT_SYMBOL(do_SAK);
+
+static int dev_match_devt(struct device *dev, void *data)
+{
+       dev_t *devt = data;
+       return dev->devt == *devt;
+}
+
+/* Must put_device() after it's unused! */
+static struct device *tty_get_device(struct tty_struct *tty)
+{
+       dev_t devt = tty_devnum(tty);
+       return class_find_device(tty_class, NULL, &devt, dev_match_devt);
+}
+
+
+/**
+ *     initialize_tty_struct
+ *     @tty: tty to initialize
+ *
+ *     This subroutine initializes a tty structure that has been newly
+ *     allocated.
+ *
+ *     Locking: none - tty in question must not be exposed at this point
+ */
+
+void initialize_tty_struct(struct tty_struct *tty,
+               struct tty_driver *driver, int idx)
+{
+       memset(tty, 0, sizeof(struct tty_struct));
+       kref_init(&tty->kref);
+       tty->magic = TTY_MAGIC;
+       tty_ldisc_init(tty);
+       tty->session = NULL;
+       tty->pgrp = NULL;
+       tty->overrun_time = jiffies;
+       tty->buf.head = tty->buf.tail = NULL;
+       tty_buffer_init(tty);
+       mutex_init(&tty->termios_mutex);
+       mutex_init(&tty->ldisc_mutex);
+       init_waitqueue_head(&tty->write_wait);
+       init_waitqueue_head(&tty->read_wait);
+       INIT_WORK(&tty->hangup_work, do_tty_hangup);
+       mutex_init(&tty->atomic_read_lock);
+       mutex_init(&tty->atomic_write_lock);
+       mutex_init(&tty->output_lock);
+       mutex_init(&tty->echo_lock);
+       spin_lock_init(&tty->read_lock);
+       spin_lock_init(&tty->ctrl_lock);
+       INIT_LIST_HEAD(&tty->tty_files);
+       INIT_WORK(&tty->SAK_work, do_SAK_work);
+
+       tty->driver = driver;
+       tty->ops = driver->ops;
+       tty->index = idx;
+       tty_line_name(driver, idx, tty->name);
+       tty->dev = tty_get_device(tty);
+}
+
+/**
+ *     tty_put_char    -       write one character to a tty
+ *     @tty: tty
+ *     @ch: character
+ *
+ *     Write one byte to the tty using the provided put_char method
+ *     if present. Returns the number of characters successfully output.
+ *
+ *     Note: the specific put_char operation in the driver layer may go
+ *     away soon. Don't call it directly, use this method
+ */
+
+int tty_put_char(struct tty_struct *tty, unsigned char ch)
+{
+       if (tty->ops->put_char)
+               return tty->ops->put_char(tty, ch);
+       return tty->ops->write(tty, &ch, 1);
+}
+EXPORT_SYMBOL_GPL(tty_put_char);
+
+struct class *tty_class;
+
+/**
+ *     tty_register_device - register a tty device
+ *     @driver: the tty driver that describes the tty device
+ *     @index: the index in the tty driver for this tty device
+ *     @device: a struct device that is associated with this tty device.
+ *             This field is optional, if there is no known struct device
+ *             for this tty device it can be set to NULL safely.
+ *
+ *     Returns a pointer to the struct device for this tty device
+ *     (or ERR_PTR(-EFOO) on error).
+ *
+ *     This call is required to be made to register an individual tty device
+ *     if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set.  If
+ *     that bit is not set, this function should not be called by a tty
+ *     driver.
+ *
+ *     Locking: ??
+ */
+
+struct device *tty_register_device(struct tty_driver *driver, unsigned index,
+                                  struct device *device)
+{
+       char name[64];
+       dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
+
+       if (index >= driver->num) {
+               printk(KERN_ERR "Attempt to register invalid tty line number "
+                      " (%d).\n", index);
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (driver->type == TTY_DRIVER_TYPE_PTY)
+               pty_line_name(driver, index, name);
+       else
+               tty_line_name(driver, index, name);
+
+       return device_create(tty_class, device, dev, NULL, name);
+}
+EXPORT_SYMBOL(tty_register_device);
+
+/**
+ *     tty_unregister_device - unregister a tty device
+ *     @driver: the tty driver that describes the tty device
+ *     @index: the index in the tty driver for this tty device
+ *
+ *     If a tty device is registered with a call to tty_register_device() then
+ *     this function must be called when the tty device is gone.
+ *
+ *     Locking: ??
+ */
+
+void tty_unregister_device(struct tty_driver *driver, unsigned index)
+{
+       device_destroy(tty_class,
+               MKDEV(driver->major, driver->minor_start) + index);
+}
+EXPORT_SYMBOL(tty_unregister_device);
+
+struct tty_driver *alloc_tty_driver(int lines)
+{
+       struct tty_driver *driver;
+
+       driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
+       if (driver) {
+               kref_init(&driver->kref);
+               driver->magic = TTY_DRIVER_MAGIC;
+               driver->num = lines;
+               /* later we'll move allocation of tables here */
+       }
+       return driver;
+}
+EXPORT_SYMBOL(alloc_tty_driver);
+
+static void destruct_tty_driver(struct kref *kref)
+{
+       struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
+       int i;
+       struct ktermios *tp;
+       void *p;
+
+       if (driver->flags & TTY_DRIVER_INSTALLED) {
+               /*
+                * Free the termios and termios_locked structures because
+                * we don't want to get memory leaks when modular tty
+                * drivers are removed from the kernel.
+                */
+               for (i = 0; i < driver->num; i++) {
+                       tp = driver->termios[i];
+                       if (tp) {
+                               driver->termios[i] = NULL;
+                               kfree(tp);
+                       }
+                       if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
+                               tty_unregister_device(driver, i);
+               }
+               p = driver->ttys;
+               proc_tty_unregister_driver(driver);
+               driver->ttys = NULL;
+               driver->termios = NULL;
+               kfree(p);
+               cdev_del(&driver->cdev);
+       }
+       kfree(driver);
+}
+
+void tty_driver_kref_put(struct tty_driver *driver)
+{
+       kref_put(&driver->kref, destruct_tty_driver);
+}
+EXPORT_SYMBOL(tty_driver_kref_put);
+
+void tty_set_operations(struct tty_driver *driver,
+                       const struct tty_operations *op)
+{
+       driver->ops = op;
+};
+EXPORT_SYMBOL(tty_set_operations);
+
+void put_tty_driver(struct tty_driver *d)
+{
+       tty_driver_kref_put(d);
+}
+EXPORT_SYMBOL(put_tty_driver);
+
+/*
+ * Called by a tty driver to register itself.
+ */
+int tty_register_driver(struct tty_driver *driver)
+{
+       int error;
+       int i;
+       dev_t dev;
+       void **p = NULL;
+       struct device *d;
+
+       if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
+               p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
+               if (!p)
+                       return -ENOMEM;
+       }
+
+       if (!driver->major) {
+               error = alloc_chrdev_region(&dev, driver->minor_start,
+                                               driver->num, driver->name);
+               if (!error) {
+                       driver->major = MAJOR(dev);
+                       driver->minor_start = MINOR(dev);
+               }
+       } else {
+               dev = MKDEV(driver->major, driver->minor_start);
+               error = register_chrdev_region(dev, driver->num, driver->name);
+       }
+       if (error < 0) {
+               kfree(p);
+               return error;
+       }
+
+       if (p) {
+               driver->ttys = (struct tty_struct **)p;
+               driver->termios = (struct ktermios **)(p + driver->num);
+       } else {
+               driver->ttys = NULL;
+               driver->termios = NULL;
+       }
+
+       cdev_init(&driver->cdev, &tty_fops);
+       driver->cdev.owner = driver->owner;
+       error = cdev_add(&driver->cdev, dev, driver->num);
+       if (error) {
+               unregister_chrdev_region(dev, driver->num);
+               driver->ttys = NULL;
+               driver->termios = NULL;
+               kfree(p);
+               return error;
+       }
+
+       mutex_lock(&tty_mutex);
+       list_add(&driver->tty_drivers, &tty_drivers);
+       mutex_unlock(&tty_mutex);
+
+       if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
+               for (i = 0; i < driver->num; i++) {
+                       d = tty_register_device(driver, i, NULL);
+                       if (IS_ERR(d)) {
+                               error = PTR_ERR(d);
+                               goto err;
+                       }
+               }
+       }
+       proc_tty_register_driver(driver);
+       driver->flags |= TTY_DRIVER_INSTALLED;
+       return 0;
+
+err:
+       for (i--; i >= 0; i--)
+               tty_unregister_device(driver, i);
+
+       mutex_lock(&tty_mutex);
+       list_del(&driver->tty_drivers);
+       mutex_unlock(&tty_mutex);
+
+       unregister_chrdev_region(dev, driver->num);
+       driver->ttys = NULL;
+       driver->termios = NULL;
+       kfree(p);
+       return error;
+}
+
+EXPORT_SYMBOL(tty_register_driver);
+
+/*
+ * Called by a tty driver to unregister itself.
+ */
+int tty_unregister_driver(struct tty_driver *driver)
+{
+#if 0
+       /* FIXME */
+       if (driver->refcount)
+               return -EBUSY;
+#endif
+       unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
+                               driver->num);
+       mutex_lock(&tty_mutex);
+       list_del(&driver->tty_drivers);
+       mutex_unlock(&tty_mutex);
+       return 0;
+}
+
+EXPORT_SYMBOL(tty_unregister_driver);
+
+dev_t tty_devnum(struct tty_struct *tty)
+{
+       return MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index;
+}
+EXPORT_SYMBOL(tty_devnum);
+
+void proc_clear_tty(struct task_struct *p)
+{
+       unsigned long flags;
+       struct tty_struct *tty;
+       spin_lock_irqsave(&p->sighand->siglock, flags);
+       tty = p->signal->tty;
+       p->signal->tty = NULL;
+       spin_unlock_irqrestore(&p->sighand->siglock, flags);
+       tty_kref_put(tty);
+}
+
+/* Called under the sighand lock */
+
+static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+{
+       if (tty) {
+               unsigned long flags;
+               /* We should not have a session or pgrp to put here but.... */
+               spin_lock_irqsave(&tty->ctrl_lock, flags);
+               put_pid(tty->session);
+               put_pid(tty->pgrp);
+               tty->pgrp = get_pid(task_pgrp(tsk));
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               tty->session = get_pid(task_session(tsk));
+               if (tsk->signal->tty) {
+                       printk(KERN_DEBUG "tty not NULL!!\n");
+                       tty_kref_put(tsk->signal->tty);
+               }
+       }
+       put_pid(tsk->signal->tty_old_pgrp);
+       tsk->signal->tty = tty_kref_get(tty);
+       tsk->signal->tty_old_pgrp = NULL;
+}
+
+static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+{
+       spin_lock_irq(&tsk->sighand->siglock);
+       __proc_set_tty(tsk, tty);
+       spin_unlock_irq(&tsk->sighand->siglock);
+}
+
+struct tty_struct *get_current_tty(void)
+{
+       struct tty_struct *tty;
+       unsigned long flags;
+
+       spin_lock_irqsave(&current->sighand->siglock, flags);
+       tty = tty_kref_get(current->signal->tty);
+       spin_unlock_irqrestore(&current->sighand->siglock, flags);
+       return tty;
+}
+EXPORT_SYMBOL_GPL(get_current_tty);
+
+void tty_default_fops(struct file_operations *fops)
+{
+       *fops = tty_fops;
+}
+
+/*
+ * Initialize the console device. This is called *early*, so
+ * we can't necessarily depend on lots of kernel help here.
+ * Just do some early initializations, and do the complex setup
+ * later.
+ */
+void __init console_init(void)
+{
+       initcall_t *call;
+
+       /* Setup the default TTY line discipline. */
+       tty_ldisc_begin();
+
+       /*
+        * set up the console device so that later boot sequences can
+        * inform about problems etc..
+        */
+       call = __con_initcall_start;
+       while (call < __con_initcall_end) {
+               (*call)();
+               call++;
+       }
+}
+
+static char *tty_devnode(struct device *dev, mode_t *mode)
+{
+       if (!mode)
+               return NULL;
+       if (dev->devt == MKDEV(TTYAUX_MAJOR, 0) ||
+           dev->devt == MKDEV(TTYAUX_MAJOR, 2))
+               *mode = 0666;
+       return NULL;
+}
+
+static int __init tty_class_init(void)
+{
+       tty_class = class_create(THIS_MODULE, "tty");
+       if (IS_ERR(tty_class))
+               return PTR_ERR(tty_class);
+       tty_class->devnode = tty_devnode;
+       return 0;
+}
+
+postcore_initcall(tty_class_init);
+
+/* 3/2004 jmc: why do these devices exist? */
+
+static struct cdev tty_cdev, console_cdev;
+
+/*
+ * Ok, now we can initialize the rest of the tty devices and can count
+ * on memory allocations, interrupts etc..
+ */
+int __init tty_init(void)
+{
+       cdev_init(&tty_cdev, &tty_fops);
+       if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
+           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
+               panic("Couldn't register /dev/tty driver\n");
+       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL,
+                             "tty");
+
+       cdev_init(&console_cdev, &console_fops);
+       if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
+           register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
+               panic("Couldn't register /dev/console driver\n");
+       device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL,
+                             "console");
+
+#ifdef CONFIG_VT
+       vty_init(&console_fops);
+#endif
+       return 0;
+}
+
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
new file mode 100644 (file)
index 0000000..0c18899
--- /dev/null
@@ -0,0 +1,1179 @@
+/*
+ *  linux/drivers/char/tty_ioctl.c
+ *
+ *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
+ * which can be dynamically activated and de-activated by the line
+ * discipline handling modules (like SLIP).
+ */
+
+#include <linux/types.h>
+#include <linux/termios.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/tty.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/mutex.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#undef TTY_DEBUG_WAIT_UNTIL_SENT
+
+#undef DEBUG
+
+/*
+ * Internal flag options for termios setting behavior
+ */
+#define TERMIOS_FLUSH  1
+#define TERMIOS_WAIT   2
+#define TERMIOS_TERMIO 4
+#define TERMIOS_OLD    8
+
+
+/**
+ *     tty_chars_in_buffer     -       characters pending
+ *     @tty: terminal
+ *
+ *     Return the number of bytes of data in the device private
+ *     output queue. If no private method is supplied there is assumed
+ *     to be no queue on the device.
+ */
+
+int tty_chars_in_buffer(struct tty_struct *tty)
+{
+       if (tty->ops->chars_in_buffer)
+               return tty->ops->chars_in_buffer(tty);
+       else
+               return 0;
+}
+EXPORT_SYMBOL(tty_chars_in_buffer);
+
+/**
+ *     tty_write_room          -       write queue space
+ *     @tty: terminal
+ *
+ *     Return the number of bytes that can be queued to this device
+ *     at the present time. The result should be treated as a guarantee
+ *     and the driver cannot offer a value it later shrinks by more than
+ *     the number of bytes written. If no method is provided 2K is always
+ *     returned and data may be lost as there will be no flow control.
+ */
+int tty_write_room(struct tty_struct *tty)
+{
+       if (tty->ops->write_room)
+               return tty->ops->write_room(tty);
+       return 2048;
+}
+EXPORT_SYMBOL(tty_write_room);
+
+/**
+ *     tty_driver_flush_buffer -       discard internal buffer
+ *     @tty: terminal
+ *
+ *     Discard the internal output buffer for this device. If no method
+ *     is provided then either the buffer cannot be hardware flushed or
+ *     there is no buffer driver side.
+ */
+void tty_driver_flush_buffer(struct tty_struct *tty)
+{
+       if (tty->ops->flush_buffer)
+               tty->ops->flush_buffer(tty);
+}
+EXPORT_SYMBOL(tty_driver_flush_buffer);
+
+/**
+ *     tty_throttle            -       flow control
+ *     @tty: terminal
+ *
+ *     Indicate that a tty should stop transmitting data down the stack.
+ *     Takes the termios mutex to protect against parallel throttle/unthrottle
+ *     and also to ensure the driver can consistently reference its own
+ *     termios data at this point when implementing software flow control.
+ */
+
+void tty_throttle(struct tty_struct *tty)
+{
+       mutex_lock(&tty->termios_mutex);
+       /* check TTY_THROTTLED first so it indicates our state */
+       if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
+           tty->ops->throttle)
+               tty->ops->throttle(tty);
+       mutex_unlock(&tty->termios_mutex);
+}
+EXPORT_SYMBOL(tty_throttle);
+
+/**
+ *     tty_unthrottle          -       flow control
+ *     @tty: terminal
+ *
+ *     Indicate that a tty may continue transmitting data down the stack.
+ *     Takes the termios mutex to protect against parallel throttle/unthrottle
+ *     and also to ensure the driver can consistently reference its own
+ *     termios data at this point when implementing software flow control.
+ *
+ *     Drivers should however remember that the stack can issue a throttle,
+ *     then change flow control method, then unthrottle.
+ */
+
+void tty_unthrottle(struct tty_struct *tty)
+{
+       mutex_lock(&tty->termios_mutex);
+       if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
+           tty->ops->unthrottle)
+               tty->ops->unthrottle(tty);
+       mutex_unlock(&tty->termios_mutex);
+}
+EXPORT_SYMBOL(tty_unthrottle);
+
+/**
+ *     tty_wait_until_sent     -       wait for I/O to finish
+ *     @tty: tty we are waiting for
+ *     @timeout: how long we will wait
+ *
+ *     Wait for characters pending in a tty driver to hit the wire, or
+ *     for a timeout to occur (eg due to flow control)
+ *
+ *     Locking: none
+ */
+
+void tty_wait_until_sent(struct tty_struct *tty, long timeout)
+{
+#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
+       char buf[64];
+
+       printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
+#endif
+       if (!timeout)
+               timeout = MAX_SCHEDULE_TIMEOUT;
+       if (wait_event_interruptible_timeout(tty->write_wait,
+                       !tty_chars_in_buffer(tty), timeout) >= 0) {
+               if (tty->ops->wait_until_sent)
+                       tty->ops->wait_until_sent(tty, timeout);
+       }
+}
+EXPORT_SYMBOL(tty_wait_until_sent);
+
+
+/*
+ *             Termios Helper Methods
+ */
+
+static void unset_locked_termios(struct ktermios *termios,
+                                struct ktermios *old,
+                                struct ktermios *locked)
+{
+       int     i;
+
+#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z)))
+
+       if (!locked) {
+               printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
+               return;
+       }
+
+       NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
+       NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
+       NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
+       NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
+       termios->c_line = locked->c_line ? old->c_line : termios->c_line;
+       for (i = 0; i < NCCS; i++)
+               termios->c_cc[i] = locked->c_cc[i] ?
+                       old->c_cc[i] : termios->c_cc[i];
+       /* FIXME: What should we do for i/ospeed */
+}
+
+/*
+ * Routine which returns the baud rate of the tty
+ *
+ * Note that the baud_table needs to be kept in sync with the
+ * include/asm/termbits.h file.
+ */
+static const speed_t baud_table[] = {
+       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+       9600, 19200, 38400, 57600, 115200, 230400, 460800,
+#ifdef __sparc__
+       76800, 153600, 307200, 614400, 921600
+#else
+       500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
+       2500000, 3000000, 3500000, 4000000
+#endif
+};
+
+#ifndef __sparc__
+static const tcflag_t baud_bits[] = {
+       B0, B50, B75, B110, B134, B150, B200, B300, B600,
+       B1200, B1800, B2400, B4800, B9600, B19200, B38400,
+       B57600, B115200, B230400, B460800, B500000, B576000,
+       B921600, B1000000, B1152000, B1500000, B2000000, B2500000,
+       B3000000, B3500000, B4000000
+};
+#else
+static const tcflag_t baud_bits[] = {
+       B0, B50, B75, B110, B134, B150, B200, B300, B600,
+       B1200, B1800, B2400, B4800, B9600, B19200, B38400,
+       B57600, B115200, B230400, B460800, B76800, B153600,
+       B307200, B614400, B921600
+};
+#endif
+
+static int n_baud_table = ARRAY_SIZE(baud_table);
+
+/**
+ *     tty_termios_baud_rate
+ *     @termios: termios structure
+ *
+ *     Convert termios baud rate data into a speed. This should be called
+ *     with the termios lock held if this termios is a terminal termios
+ *     structure. May change the termios data. Device drivers can call this
+ *     function but should use ->c_[io]speed directly as they are updated.
+ *
+ *     Locking: none
+ */
+
+speed_t tty_termios_baud_rate(struct ktermios *termios)
+{
+       unsigned int cbaud;
+
+       cbaud = termios->c_cflag & CBAUD;
+
+#ifdef BOTHER
+       /* Magic token for arbitary speed via c_ispeed/c_ospeed */
+       if (cbaud == BOTHER)
+               return termios->c_ospeed;
+#endif
+       if (cbaud & CBAUDEX) {
+               cbaud &= ~CBAUDEX;
+
+               if (cbaud < 1 || cbaud + 15 > n_baud_table)
+                       termios->c_cflag &= ~CBAUDEX;
+               else
+                       cbaud += 15;
+       }
+       return baud_table[cbaud];
+}
+EXPORT_SYMBOL(tty_termios_baud_rate);
+
+/**
+ *     tty_termios_input_baud_rate
+ *     @termios: termios structure
+ *
+ *     Convert termios baud rate data into a speed. This should be called
+ *     with the termios lock held if this termios is a terminal termios
+ *     structure. May change the termios data. Device drivers can call this
+ *     function but should use ->c_[io]speed directly as they are updated.
+ *
+ *     Locking: none
+ */
+
+speed_t tty_termios_input_baud_rate(struct ktermios *termios)
+{
+#ifdef IBSHIFT
+       unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD;
+
+       if (cbaud == B0)
+               return tty_termios_baud_rate(termios);
+
+       /* Magic token for arbitary speed via c_ispeed*/
+       if (cbaud == BOTHER)
+               return termios->c_ispeed;
+
+       if (cbaud & CBAUDEX) {
+               cbaud &= ~CBAUDEX;
+
+               if (cbaud < 1 || cbaud + 15 > n_baud_table)
+                       termios->c_cflag &= ~(CBAUDEX << IBSHIFT);
+               else
+                       cbaud += 15;
+       }
+       return baud_table[cbaud];
+#else
+       return tty_termios_baud_rate(termios);
+#endif
+}
+EXPORT_SYMBOL(tty_termios_input_baud_rate);
+
+/**
+ *     tty_termios_encode_baud_rate
+ *     @termios: ktermios structure holding user requested state
+ *     @ispeed: input speed
+ *     @ospeed: output speed
+ *
+ *     Encode the speeds set into the passed termios structure. This is
+ *     used as a library helper for drivers os that they can report back
+ *     the actual speed selected when it differs from the speed requested
+ *
+ *     For maximal back compatibility with legacy SYS5/POSIX *nix behaviour
+ *     we need to carefully set the bits when the user does not get the
+ *     desired speed. We allow small margins and preserve as much of possible
+ *     of the input intent to keep compatibility.
+ *
+ *     Locking: Caller should hold termios lock. This is already held
+ *     when calling this function from the driver termios handler.
+ *
+ *     The ifdefs deal with platforms whose owners have yet to update them
+ *     and will all go away once this is done.
+ */
+
+void tty_termios_encode_baud_rate(struct ktermios *termios,
+                                 speed_t ibaud, speed_t obaud)
+{
+       int i = 0;
+       int ifound = -1, ofound = -1;
+       int iclose = ibaud/50, oclose = obaud/50;
+       int ibinput = 0;
+
+       if (obaud == 0)                 /* CD dropped             */
+               ibaud = 0;              /* Clear ibaud to be sure */
+
+       termios->c_ispeed = ibaud;
+       termios->c_ospeed = obaud;
+
+#ifdef BOTHER
+       /* If the user asked for a precise weird speed give a precise weird
+          answer. If they asked for a Bfoo speed they many have problems
+          digesting non-exact replies so fuzz a bit */
+
+       if ((termios->c_cflag & CBAUD) == BOTHER)
+               oclose = 0;
+       if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER)
+               iclose = 0;
+       if ((termios->c_cflag >> IBSHIFT) & CBAUD)
+               ibinput = 1;    /* An input speed was specified */
+#endif
+       termios->c_cflag &= ~CBAUD;
+
+       /*
+        *      Our goal is to find a close match to the standard baud rate
+        *      returned. Walk the baud rate table and if we get a very close
+        *      match then report back the speed as a POSIX Bxxxx value by
+        *      preference
+        */
+
+       do {
+               if (obaud - oclose <= baud_table[i] &&
+                   obaud + oclose >= baud_table[i]) {
+                       termios->c_cflag |= baud_bits[i];
+                       ofound = i;
+               }
+               if (ibaud - iclose <= baud_table[i] &&
+                   ibaud + iclose >= baud_table[i]) {
+                       /* For the case input == output don't set IBAUD bits
+                          if the user didn't do so */
+                       if (ofound == i && !ibinput)
+                               ifound  = i;
+#ifdef IBSHIFT
+                       else {
+                               ifound = i;
+                               termios->c_cflag |= (baud_bits[i] << IBSHIFT);
+                       }
+#endif
+               }
+       } while (++i < n_baud_table);
+
+       /*
+        *      If we found no match then use BOTHER if provided or warn
+        *      the user their platform maintainer needs to wake up if not.
+        */
+#ifdef BOTHER
+       if (ofound == -1)
+               termios->c_cflag |= BOTHER;
+       /* Set exact input bits only if the input and output differ or the
+          user already did */
+       if (ifound == -1 && (ibaud != obaud || ibinput))
+               termios->c_cflag |= (BOTHER << IBSHIFT);
+#else
+       if (ifound == -1 || ofound == -1) {
+               printk_once(KERN_WARNING "tty: Unable to return correct "
+                         "speed data as your architecture needs updating.\n");
+       }
+#endif
+}
+EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
+
+/**
+ *     tty_encode_baud_rate            -       set baud rate of the tty
+ *     @ibaud: input baud rate
+ *     @obad: output baud rate
+ *
+ *     Update the current termios data for the tty with the new speed
+ *     settings. The caller must hold the termios_mutex for the tty in
+ *     question.
+ */
+
+void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
+{
+       tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
+}
+EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
+
+/**
+ *     tty_get_baud_rate       -       get tty bit rates
+ *     @tty: tty to query
+ *
+ *     Returns the baud rate as an integer for this terminal. The
+ *     termios lock must be held by the caller and the terminal bit
+ *     flags may be updated.
+ *
+ *     Locking: none
+ */
+
+speed_t tty_get_baud_rate(struct tty_struct *tty)
+{
+       speed_t baud = tty_termios_baud_rate(tty->termios);
+
+       if (baud == 38400 && tty->alt_speed) {
+               if (!tty->warned) {
+                       printk(KERN_WARNING "Use of setserial/setrocket to "
+                                           "set SPD_* flags is deprecated\n");
+                       tty->warned = 1;
+               }
+               baud = tty->alt_speed;
+       }
+
+       return baud;
+}
+EXPORT_SYMBOL(tty_get_baud_rate);
+
+/**
+ *     tty_termios_copy_hw     -       copy hardware settings
+ *     @new: New termios
+ *     @old: Old termios
+ *
+ *     Propogate the hardware specific terminal setting bits from
+ *     the old termios structure to the new one. This is used in cases
+ *     where the hardware does not support reconfiguration or as a helper
+ *     in some cases where only minimal reconfiguration is supported
+ */
+
+void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old)
+{
+       /* The bits a dumb device handles in software. Smart devices need
+          to always provide a set_termios method */
+       new->c_cflag &= HUPCL | CREAD | CLOCAL;
+       new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL);
+       new->c_ispeed = old->c_ispeed;
+       new->c_ospeed = old->c_ospeed;
+}
+EXPORT_SYMBOL(tty_termios_copy_hw);
+
+/**
+ *     tty_termios_hw_change   -       check for setting change
+ *     @a: termios
+ *     @b: termios to compare
+ *
+ *     Check if any of the bits that affect a dumb device have changed
+ *     between the two termios structures, or a speed change is needed.
+ */
+
+int tty_termios_hw_change(struct ktermios *a, struct ktermios *b)
+{
+       if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed)
+               return 1;
+       if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL))
+               return 1;
+       return 0;
+}
+EXPORT_SYMBOL(tty_termios_hw_change);
+
+/**
+ *     change_termios          -       update termios values
+ *     @tty: tty to update
+ *     @new_termios: desired new value
+ *
+ *     Perform updates to the termios values set on this terminal. There
+ *     is a bit of layering violation here with n_tty in terms of the
+ *     internal knowledge of this function.
+ *
+ *     Locking: termios_mutex
+ */
+
+static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
+{
+       struct ktermios old_termios;
+       struct tty_ldisc *ld;
+       unsigned long flags;
+
+       /*
+        *      Perform the actual termios internal changes under lock.
+        */
+
+
+       /* FIXME: we need to decide on some locking/ordering semantics
+          for the set_termios notification eventually */
+       mutex_lock(&tty->termios_mutex);
+       old_termios = *tty->termios;
+       *tty->termios = *new_termios;
+       unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
+
+       /* See if packet mode change of state. */
+       if (tty->link && tty->link->packet) {
+               int extproc = (old_termios.c_lflag & EXTPROC) |
+                               (tty->termios->c_lflag & EXTPROC);
+               int old_flow = ((old_termios.c_iflag & IXON) &&
+                               (old_termios.c_cc[VSTOP] == '\023') &&
+                               (old_termios.c_cc[VSTART] == '\021'));
+               int new_flow = (I_IXON(tty) &&
+                               STOP_CHAR(tty) == '\023' &&
+                               START_CHAR(tty) == '\021');
+               if ((old_flow != new_flow) || extproc) {
+                       spin_lock_irqsave(&tty->ctrl_lock, flags);
+                       if (old_flow != new_flow) {
+                               tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
+                               if (new_flow)
+                                       tty->ctrl_status |= TIOCPKT_DOSTOP;
+                               else
+                                       tty->ctrl_status |= TIOCPKT_NOSTOP;
+                       }
+                       if (extproc)
+                               tty->ctrl_status |= TIOCPKT_IOCTL;
+                       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+                       wake_up_interruptible(&tty->link->read_wait);
+               }
+       }
+
+       if (tty->ops->set_termios)
+               (*tty->ops->set_termios)(tty, &old_termios);
+       else
+               tty_termios_copy_hw(tty->termios, &old_termios);
+
+       ld = tty_ldisc_ref(tty);
+       if (ld != NULL) {
+               if (ld->ops->set_termios)
+                       (ld->ops->set_termios)(tty, &old_termios);
+               tty_ldisc_deref(ld);
+       }
+       mutex_unlock(&tty->termios_mutex);
+}
+
+/**
+ *     set_termios             -       set termios values for a tty
+ *     @tty: terminal device
+ *     @arg: user data
+ *     @opt: option information
+ *
+ *     Helper function to prepare termios data and run necessary other
+ *     functions before using change_termios to do the actual changes.
+ *
+ *     Locking:
+ *             Called functions take ldisc and termios_mutex locks
+ */
+
+static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
+{
+       struct ktermios tmp_termios;
+       struct tty_ldisc *ld;
+       int retval = tty_check_change(tty);
+
+       if (retval)
+               return retval;
+
+       mutex_lock(&tty->termios_mutex);
+       memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
+       mutex_unlock(&tty->termios_mutex);
+
+       if (opt & TERMIOS_TERMIO) {
+               if (user_termio_to_kernel_termios(&tmp_termios,
+                                               (struct termio __user *)arg))
+                       return -EFAULT;
+#ifdef TCGETS2
+       } else if (opt & TERMIOS_OLD) {
+               if (user_termios_to_kernel_termios_1(&tmp_termios,
+                                               (struct termios __user *)arg))
+                       return -EFAULT;
+       } else {
+               if (user_termios_to_kernel_termios(&tmp_termios,
+                                               (struct termios2 __user *)arg))
+                       return -EFAULT;
+       }
+#else
+       } else if (user_termios_to_kernel_termios(&tmp_termios,
+                                       (struct termios __user *)arg))
+               return -EFAULT;
+#endif
+
+       /* If old style Bfoo values are used then load c_ispeed/c_ospeed
+        * with the real speed so its unconditionally usable */
+       tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios);
+       tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios);
+
+       ld = tty_ldisc_ref(tty);
+
+       if (ld != NULL) {
+               if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               tty_ldisc_deref(ld);
+       }
+
+       if (opt & TERMIOS_WAIT) {
+               tty_wait_until_sent(tty, 0);
+               if (signal_pending(current))
+                       return -EINTR;
+       }
+
+       change_termios(tty, &tmp_termios);
+
+       /* FIXME: Arguably if tmp_termios == tty->termios AND the
+          actual requested termios was not tmp_termios then we may
+          want to return an error as no user requested change has
+          succeeded */
+       return 0;
+}
+
+static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
+{
+       mutex_lock(&tty->termios_mutex);
+       memcpy(kterm, tty->termios, sizeof(struct ktermios));
+       mutex_unlock(&tty->termios_mutex);
+}
+
+static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
+{
+       mutex_lock(&tty->termios_mutex);
+       memcpy(kterm, tty->termios_locked, sizeof(struct ktermios));
+       mutex_unlock(&tty->termios_mutex);
+}
+
+static int get_termio(struct tty_struct *tty, struct termio __user *termio)
+{
+       struct ktermios kterm;
+       copy_termios(tty, &kterm);
+       if (kernel_termios_to_user_termio(termio, &kterm))
+               return -EFAULT;
+       return 0;
+}
+
+
+#ifdef TCGETX
+
+/**
+ *     set_termiox     -       set termiox fields if possible
+ *     @tty: terminal
+ *     @arg: termiox structure from user
+ *     @opt: option flags for ioctl type
+ *
+ *     Implement the device calling points for the SYS5 termiox ioctl
+ *     interface in Linux
+ */
+
+static int set_termiox(struct tty_struct *tty, void __user *arg, int opt)
+{
+       struct termiox tnew;
+       struct tty_ldisc *ld;
+
+       if (tty->termiox == NULL)
+               return -EINVAL;
+       if (copy_from_user(&tnew, arg, sizeof(struct termiox)))
+               return -EFAULT;
+
+       ld = tty_ldisc_ref(tty);
+       if (ld != NULL) {
+               if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               tty_ldisc_deref(ld);
+       }
+       if (opt & TERMIOS_WAIT) {
+               tty_wait_until_sent(tty, 0);
+               if (signal_pending(current))
+                       return -EINTR;
+       }
+
+       mutex_lock(&tty->termios_mutex);
+       if (tty->ops->set_termiox)
+               tty->ops->set_termiox(tty, &tnew);
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
+}
+
+#endif
+
+
+#ifdef TIOCGETP
+/*
+ * These are deprecated, but there is limited support..
+ *
+ * The "sg_flags" translation is a joke..
+ */
+static int get_sgflags(struct tty_struct *tty)
+{
+       int flags = 0;
+
+       if (!(tty->termios->c_lflag & ICANON)) {
+               if (tty->termios->c_lflag & ISIG)
+                       flags |= 0x02;          /* cbreak */
+               else
+                       flags |= 0x20;          /* raw */
+       }
+       if (tty->termios->c_lflag & ECHO)
+               flags |= 0x08;                  /* echo */
+       if (tty->termios->c_oflag & OPOST)
+               if (tty->termios->c_oflag & ONLCR)
+                       flags |= 0x10;          /* crmod */
+       return flags;
+}
+
+static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
+{
+       struct sgttyb tmp;
+
+       mutex_lock(&tty->termios_mutex);
+       tmp.sg_ispeed = tty->termios->c_ispeed;
+       tmp.sg_ospeed = tty->termios->c_ospeed;
+       tmp.sg_erase = tty->termios->c_cc[VERASE];
+       tmp.sg_kill = tty->termios->c_cc[VKILL];
+       tmp.sg_flags = get_sgflags(tty);
+       mutex_unlock(&tty->termios_mutex);
+
+       return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
+}
+
+static void set_sgflags(struct ktermios *termios, int flags)
+{
+       termios->c_iflag = ICRNL | IXON;
+       termios->c_oflag = 0;
+       termios->c_lflag = ISIG | ICANON;
+       if (flags & 0x02) {     /* cbreak */
+               termios->c_iflag = 0;
+               termios->c_lflag &= ~ICANON;
+       }
+       if (flags & 0x08) {             /* echo */
+               termios->c_lflag |= ECHO | ECHOE | ECHOK |
+                                   ECHOCTL | ECHOKE | IEXTEN;
+       }
+       if (flags & 0x10) {             /* crmod */
+               termios->c_oflag |= OPOST | ONLCR;
+       }
+       if (flags & 0x20) {     /* raw */
+               termios->c_iflag = 0;
+               termios->c_lflag &= ~(ISIG | ICANON);
+       }
+       if (!(termios->c_lflag & ICANON)) {
+               termios->c_cc[VMIN] = 1;
+               termios->c_cc[VTIME] = 0;
+       }
+}
+
+/**
+ *     set_sgttyb              -       set legacy terminal values
+ *     @tty: tty structure
+ *     @sgttyb: pointer to old style terminal structure
+ *
+ *     Updates a terminal from the legacy BSD style terminal information
+ *     structure.
+ *
+ *     Locking: termios_mutex
+ */
+
+static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
+{
+       int retval;
+       struct sgttyb tmp;
+       struct ktermios termios;
+
+       retval = tty_check_change(tty);
+       if (retval)
+               return retval;
+
+       if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
+               return -EFAULT;
+
+       mutex_lock(&tty->termios_mutex);
+       termios = *tty->termios;
+       termios.c_cc[VERASE] = tmp.sg_erase;
+       termios.c_cc[VKILL] = tmp.sg_kill;
+       set_sgflags(&termios, tmp.sg_flags);
+       /* Try and encode into Bfoo format */
+#ifdef BOTHER
+       tty_termios_encode_baud_rate(&termios, termios.c_ispeed,
+                                               termios.c_ospeed);
+#endif
+       mutex_unlock(&tty->termios_mutex);
+       change_termios(tty, &termios);
+       return 0;
+}
+#endif
+
+#ifdef TIOCGETC
+static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
+{
+       struct tchars tmp;
+
+       mutex_lock(&tty->termios_mutex);
+       tmp.t_intrc = tty->termios->c_cc[VINTR];
+       tmp.t_quitc = tty->termios->c_cc[VQUIT];
+       tmp.t_startc = tty->termios->c_cc[VSTART];
+       tmp.t_stopc = tty->termios->c_cc[VSTOP];
+       tmp.t_eofc = tty->termios->c_cc[VEOF];
+       tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
+       mutex_unlock(&tty->termios_mutex);
+       return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
+}
+
+static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
+{
+       struct tchars tmp;
+
+       if (copy_from_user(&tmp, tchars, sizeof(tmp)))
+               return -EFAULT;
+       mutex_lock(&tty->termios_mutex);
+       tty->termios->c_cc[VINTR] = tmp.t_intrc;
+       tty->termios->c_cc[VQUIT] = tmp.t_quitc;
+       tty->termios->c_cc[VSTART] = tmp.t_startc;
+       tty->termios->c_cc[VSTOP] = tmp.t_stopc;
+       tty->termios->c_cc[VEOF] = tmp.t_eofc;
+       tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
+}
+#endif
+
+#ifdef TIOCGLTC
+static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
+{
+       struct ltchars tmp;
+
+       mutex_lock(&tty->termios_mutex);
+       tmp.t_suspc = tty->termios->c_cc[VSUSP];
+       /* what is dsuspc anyway? */
+       tmp.t_dsuspc = tty->termios->c_cc[VSUSP];
+       tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
+       /* what is flushc anyway? */
+       tmp.t_flushc = tty->termios->c_cc[VEOL2];
+       tmp.t_werasc = tty->termios->c_cc[VWERASE];
+       tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
+       mutex_unlock(&tty->termios_mutex);
+       return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
+}
+
+static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
+{
+       struct ltchars tmp;
+
+       if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
+               return -EFAULT;
+
+       mutex_lock(&tty->termios_mutex);
+       tty->termios->c_cc[VSUSP] = tmp.t_suspc;
+       /* what is dsuspc anyway? */
+       tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;
+       tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
+       /* what is flushc anyway? */
+       tty->termios->c_cc[VEOL2] = tmp.t_flushc;
+       tty->termios->c_cc[VWERASE] = tmp.t_werasc;
+       tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
+       mutex_unlock(&tty->termios_mutex);
+       return 0;
+}
+#endif
+
+/**
+ *     send_prio_char          -       send priority character
+ *
+ *     Send a high priority character to the tty even if stopped
+ *
+ *     Locking: none for xchar method, write ordering for write method.
+ */
+
+static int send_prio_char(struct tty_struct *tty, char ch)
+{
+       int     was_stopped = tty->stopped;
+
+       if (tty->ops->send_xchar) {
+               tty->ops->send_xchar(tty, ch);
+               return 0;
+       }
+
+       if (tty_write_lock(tty, 0) < 0)
+               return -ERESTARTSYS;
+
+       if (was_stopped)
+               start_tty(tty);
+       tty->ops->write(tty, &ch, 1);
+       if (was_stopped)
+               stop_tty(tty);
+       tty_write_unlock(tty);
+       return 0;
+}
+
+/**
+ *     tty_change_softcar      -       carrier change ioctl helper
+ *     @tty: tty to update
+ *     @arg: enable/disable CLOCAL
+ *
+ *     Perform a change to the CLOCAL state and call into the driver
+ *     layer to make it visible. All done with the termios mutex
+ */
+
+static int tty_change_softcar(struct tty_struct *tty, int arg)
+{
+       int ret = 0;
+       int bit = arg ? CLOCAL : 0;
+       struct ktermios old;
+
+       mutex_lock(&tty->termios_mutex);
+       old = *tty->termios;
+       tty->termios->c_cflag &= ~CLOCAL;
+       tty->termios->c_cflag |= bit;
+       if (tty->ops->set_termios)
+               tty->ops->set_termios(tty, &old);
+       if ((tty->termios->c_cflag & CLOCAL) != bit)
+               ret = -EINVAL;
+       mutex_unlock(&tty->termios_mutex);
+       return ret;
+}
+
+/**
+ *     tty_mode_ioctl          -       mode related ioctls
+ *     @tty: tty for the ioctl
+ *     @file: file pointer for the tty
+ *     @cmd: command
+ *     @arg: ioctl argument
+ *
+ *     Perform non line discipline specific mode control ioctls. This
+ *     is designed to be called by line disciplines to ensure they provide
+ *     consistent mode setting.
+ */
+
+int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
+                       unsigned int cmd, unsigned long arg)
+{
+       struct tty_struct *real_tty;
+       void __user *p = (void __user *)arg;
+       int ret = 0;
+       struct ktermios kterm;
+
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
+           tty->driver->subtype == PTY_TYPE_MASTER)
+               real_tty = tty->link;
+       else
+               real_tty = tty;
+
+       switch (cmd) {
+#ifdef TIOCGETP
+       case TIOCGETP:
+               return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
+       case TIOCSETP:
+       case TIOCSETN:
+               return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
+#endif
+#ifdef TIOCGETC
+       case TIOCGETC:
+               return get_tchars(real_tty, p);
+       case TIOCSETC:
+               return set_tchars(real_tty, p);
+#endif
+#ifdef TIOCGLTC
+       case TIOCGLTC:
+               return get_ltchars(real_tty, p);
+       case TIOCSLTC:
+               return set_ltchars(real_tty, p);
+#endif
+       case TCSETSF:
+               return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD);
+       case TCSETSW:
+               return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD);
+       case TCSETS:
+               return set_termios(real_tty, p, TERMIOS_OLD);
+#ifndef TCGETS2
+       case TCGETS:
+               copy_termios(real_tty, &kterm);
+               if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
+                       ret = -EFAULT;
+               return ret;
+#else
+       case TCGETS:
+               copy_termios(real_tty, &kterm);
+               if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
+                       ret = -EFAULT;
+               return ret;
+       case TCGETS2:
+               copy_termios(real_tty, &kterm);
+               if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
+                       ret = -EFAULT;
+               return ret;
+       case TCSETSF2:
+               return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);
+       case TCSETSW2:
+               return set_termios(real_tty, p, TERMIOS_WAIT);
+       case TCSETS2:
+               return set_termios(real_tty, p, 0);
+#endif
+       case TCGETA:
+               return get_termio(real_tty, p);
+       case TCSETAF:
+               return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
+       case TCSETAW:
+               return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
+       case TCSETA:
+               return set_termios(real_tty, p, TERMIOS_TERMIO);
+#ifndef TCGETS2
+       case TIOCGLCKTRMIOS:
+               copy_termios_locked(real_tty, &kterm);
+               if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
+                       ret = -EFAULT;
+               return ret;
+       case TIOCSLCKTRMIOS:
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               copy_termios_locked(real_tty, &kterm);
+               if (user_termios_to_kernel_termios(&kterm,
+                                              (struct termios __user *) arg))
+                       return -EFAULT;
+               mutex_lock(&real_tty->termios_mutex);
+               memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
+               mutex_unlock(&real_tty->termios_mutex);
+               return 0;
+#else
+       case TIOCGLCKTRMIOS:
+               copy_termios_locked(real_tty, &kterm);
+               if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
+                       ret = -EFAULT;
+               return ret;
+       case TIOCSLCKTRMIOS:
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               copy_termios_locked(real_tty, &kterm);
+               if (user_termios_to_kernel_termios_1(&kterm,
+                                              (struct termios __user *) arg))
+                       return -EFAULT;
+               mutex_lock(&real_tty->termios_mutex);
+               memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
+               mutex_unlock(&real_tty->termios_mutex);
+               return ret;
+#endif
+#ifdef TCGETX
+       case TCGETX: {
+               struct termiox ktermx;
+               if (real_tty->termiox == NULL)
+                       return -EINVAL;
+               mutex_lock(&real_tty->termios_mutex);
+               memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
+               mutex_unlock(&real_tty->termios_mutex);
+               if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
+                       ret = -EFAULT;
+               return ret;
+       }
+       case TCSETX:
+               return set_termiox(real_tty, p, 0);
+       case TCSETXW:
+               return set_termiox(real_tty, p, TERMIOS_WAIT);
+       case TCSETXF:
+               return set_termiox(real_tty, p, TERMIOS_FLUSH);
+#endif         
+       case TIOCGSOFTCAR:
+               copy_termios(real_tty, &kterm);
+               ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
+                                               (int __user *)arg);
+               return ret;
+       case TIOCSSOFTCAR:
+               if (get_user(arg, (unsigned int __user *) arg))
+                       return -EFAULT;
+               return tty_change_softcar(real_tty, arg);
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+EXPORT_SYMBOL_GPL(tty_mode_ioctl);
+
+int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
+{
+       struct tty_ldisc *ld;
+       int retval = tty_check_change(tty);
+       if (retval)
+               return retval;
+
+       ld = tty_ldisc_ref_wait(tty);
+       switch (arg) {
+       case TCIFLUSH:
+               if (ld && ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               break;
+       case TCIOFLUSH:
+               if (ld && ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               /* fall through */
+       case TCOFLUSH:
+               tty_driver_flush_buffer(tty);
+               break;
+       default:
+               tty_ldisc_deref(ld);
+               return -EINVAL;
+       }
+       tty_ldisc_deref(ld);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tty_perform_flush);
+
+int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       unsigned long flags;
+       int retval;
+
+       switch (cmd) {
+       case TCXONC:
+               retval = tty_check_change(tty);
+               if (retval)
+                       return retval;
+               switch (arg) {
+               case TCOOFF:
+                       if (!tty->flow_stopped) {
+                               tty->flow_stopped = 1;
+                               stop_tty(tty);
+                       }
+                       break;
+               case TCOON:
+                       if (tty->flow_stopped) {
+                               tty->flow_stopped = 0;
+                               start_tty(tty);
+                       }
+                       break;
+               case TCIOFF:
+                       if (STOP_CHAR(tty) != __DISABLED_CHAR)
+                               return send_prio_char(tty, STOP_CHAR(tty));
+                       break;
+               case TCION:
+                       if (START_CHAR(tty) != __DISABLED_CHAR)
+                               return send_prio_char(tty, START_CHAR(tty));
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               return 0;
+       case TCFLSH:
+               return tty_perform_flush(tty, arg);
+       case TIOCPKT:
+       {
+               int pktmode;
+
+               if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
+                   tty->driver->subtype != PTY_TYPE_MASTER)
+                       return -ENOTTY;
+               if (get_user(pktmode, (int __user *) arg))
+                       return -EFAULT;
+               spin_lock_irqsave(&tty->ctrl_lock, flags);
+               if (pktmode) {
+                       if (!tty->packet) {
+                               tty->packet = 1;
+                               tty->link->ctrl_status = 0;
+                       }
+               } else
+                       tty->packet = 0;
+               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               return 0;
+       }
+       default:
+               /* Try the mode commands */
+               return tty_mode_ioctl(tty, file, cmd, arg);
+       }
+}
+EXPORT_SYMBOL(n_tty_ioctl_helper);
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
new file mode 100644 (file)
index 0000000..412f977
--- /dev/null
@@ -0,0 +1,915 @@
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/devpts_fs.h>
+#include <linux/file.h>
+#include <linux/console.h>
+#include <linux/timer.h>
+#include <linux/ctype.h>
+#include <linux/kd.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+
+#include <linux/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+
+#include <linux/smp_lock.h>    /* For the moment */
+
+#include <linux/kmod.h>
+#include <linux/nsproxy.h>
+
+/*
+ *     This guards the refcounted line discipline lists. The lock
+ *     must be taken with irqs off because there are hangup path
+ *     callers who will do ldisc lookups and cannot sleep.
+ */
+
+static DEFINE_SPINLOCK(tty_ldisc_lock);
+static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
+/* Line disc dispatch table */
+static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
+
+static inline struct tty_ldisc *get_ldisc(struct tty_ldisc *ld)
+{
+       if (ld)
+               atomic_inc(&ld->users);
+       return ld;
+}
+
+static void put_ldisc(struct tty_ldisc *ld)
+{
+       unsigned long flags;
+
+       if (WARN_ON_ONCE(!ld))
+               return;
+
+       /*
+        * If this is the last user, free the ldisc, and
+        * release the ldisc ops.
+        *
+        * We really want an "atomic_dec_and_lock_irqsave()",
+        * but we don't have it, so this does it by hand.
+        */
+       local_irq_save(flags);
+       if (atomic_dec_and_lock(&ld->users, &tty_ldisc_lock)) {
+               struct tty_ldisc_ops *ldo = ld->ops;
+
+               ldo->refcount--;
+               module_put(ldo->owner);
+               spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+               kfree(ld);
+               return;
+       }
+       local_irq_restore(flags);
+}
+
+/**
+ *     tty_register_ldisc      -       install a line discipline
+ *     @disc: ldisc number
+ *     @new_ldisc: pointer to the ldisc object
+ *
+ *     Installs a new line discipline into the kernel. The discipline
+ *     is set up as unreferenced and then made available to the kernel
+ *     from this point onwards.
+ *
+ *     Locking:
+ *             takes tty_ldisc_lock to guard against ldisc races
+ */
+
+int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       if (disc < N_TTY || disc >= NR_LDISCS)
+               return -EINVAL;
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       tty_ldiscs[disc] = new_ldisc;
+       new_ldisc->num = disc;
+       new_ldisc->refcount = 0;
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(tty_register_ldisc);
+
+/**
+ *     tty_unregister_ldisc    -       unload a line discipline
+ *     @disc: ldisc number
+ *     @new_ldisc: pointer to the ldisc object
+ *
+ *     Remove a line discipline from the kernel providing it is not
+ *     currently in use.
+ *
+ *     Locking:
+ *             takes tty_ldisc_lock to guard against ldisc races
+ */
+
+int tty_unregister_ldisc(int disc)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       if (disc < N_TTY || disc >= NR_LDISCS)
+               return -EINVAL;
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       if (tty_ldiscs[disc]->refcount)
+               ret = -EBUSY;
+       else
+               tty_ldiscs[disc] = NULL;
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(tty_unregister_ldisc);
+
+static struct tty_ldisc_ops *get_ldops(int disc)
+{
+       unsigned long flags;
+       struct tty_ldisc_ops *ldops, *ret;
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       ret = ERR_PTR(-EINVAL);
+       ldops = tty_ldiscs[disc];
+       if (ldops) {
+               ret = ERR_PTR(-EAGAIN);
+               if (try_module_get(ldops->owner)) {
+                       ldops->refcount++;
+                       ret = ldops;
+               }
+       }
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+       return ret;
+}
+
+static void put_ldops(struct tty_ldisc_ops *ldops)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       ldops->refcount--;
+       module_put(ldops->owner);
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+}
+
+/**
+ *     tty_ldisc_get           -       take a reference to an ldisc
+ *     @disc: ldisc number
+ *
+ *     Takes a reference to a line discipline. Deals with refcounts and
+ *     module locking counts. Returns NULL if the discipline is not available.
+ *     Returns a pointer to the discipline and bumps the ref count if it is
+ *     available
+ *
+ *     Locking:
+ *             takes tty_ldisc_lock to guard against ldisc races
+ */
+
+static struct tty_ldisc *tty_ldisc_get(int disc)
+{
+       struct tty_ldisc *ld;
+       struct tty_ldisc_ops *ldops;
+
+       if (disc < N_TTY || disc >= NR_LDISCS)
+               return ERR_PTR(-EINVAL);
+
+       /*
+        * Get the ldisc ops - we may need to request them to be loaded
+        * dynamically and try again.
+        */
+       ldops = get_ldops(disc);
+       if (IS_ERR(ldops)) {
+               request_module("tty-ldisc-%d", disc);
+               ldops = get_ldops(disc);
+               if (IS_ERR(ldops))
+                       return ERR_CAST(ldops);
+       }
+
+       ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
+       if (ld == NULL) {
+               put_ldops(ldops);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       ld->ops = ldops;
+       atomic_set(&ld->users, 1);
+       return ld;
+}
+
+static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
+{
+       return (*pos < NR_LDISCS) ? pos : NULL;
+}
+
+static void *tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       (*pos)++;
+       return (*pos < NR_LDISCS) ? pos : NULL;
+}
+
+static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
+{
+}
+
+static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
+{
+       int i = *(loff_t *)v;
+       struct tty_ldisc_ops *ldops;
+
+       ldops = get_ldops(i);
+       if (IS_ERR(ldops))
+               return 0;
+       seq_printf(m, "%-10s %2d\n", ldops->name ? ldops->name : "???", i);
+       put_ldops(ldops);
+       return 0;
+}
+
+static const struct seq_operations tty_ldiscs_seq_ops = {
+       .start  = tty_ldiscs_seq_start,
+       .next   = tty_ldiscs_seq_next,
+       .stop   = tty_ldiscs_seq_stop,
+       .show   = tty_ldiscs_seq_show,
+};
+
+static int proc_tty_ldiscs_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &tty_ldiscs_seq_ops);
+}
+
+const struct file_operations tty_ldiscs_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = proc_tty_ldiscs_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release,
+};
+
+/**
+ *     tty_ldisc_assign        -       set ldisc on a tty
+ *     @tty: tty to assign
+ *     @ld: line discipline
+ *
+ *     Install an instance of a line discipline into a tty structure. The
+ *     ldisc must have a reference count above zero to ensure it remains.
+ *     The tty instance refcount starts at zero.
+ *
+ *     Locking:
+ *             Caller must hold references
+ */
+
+static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
+{
+       tty->ldisc = ld;
+}
+
+/**
+ *     tty_ldisc_try           -       internal helper
+ *     @tty: the tty
+ *
+ *     Make a single attempt to grab and bump the refcount on
+ *     the tty ldisc. Return 0 on failure or 1 on success. This is
+ *     used to implement both the waiting and non waiting versions
+ *     of tty_ldisc_ref
+ *
+ *     Locking: takes tty_ldisc_lock
+ */
+
+static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
+{
+       unsigned long flags;
+       struct tty_ldisc *ld;
+
+       spin_lock_irqsave(&tty_ldisc_lock, flags);
+       ld = NULL;
+       if (test_bit(TTY_LDISC, &tty->flags))
+               ld = get_ldisc(tty->ldisc);
+       spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+       return ld;
+}
+
+/**
+ *     tty_ldisc_ref_wait      -       wait for the tty ldisc
+ *     @tty: tty device
+ *
+ *     Dereference the line discipline for the terminal and take a
+ *     reference to it. If the line discipline is in flux then
+ *     wait patiently until it changes.
+ *
+ *     Note: Must not be called from an IRQ/timer context. The caller
+ *     must also be careful not to hold other locks that will deadlock
+ *     against a discipline change, such as an existing ldisc reference
+ *     (which we check for)
+ *
+ *     Locking: call functions take tty_ldisc_lock
+ */
+
+struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
+{
+       struct tty_ldisc *ld;
+
+       /* wait_event is a macro */
+       wait_event(tty_ldisc_wait, (ld = tty_ldisc_try(tty)) != NULL);
+       return ld;
+}
+EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
+
+/**
+ *     tty_ldisc_ref           -       get the tty ldisc
+ *     @tty: tty device
+ *
+ *     Dereference the line discipline for the terminal and take a
+ *     reference to it. If the line discipline is in flux then
+ *     return NULL. Can be called from IRQ and timer functions.
+ *
+ *     Locking: called functions take tty_ldisc_lock
+ */
+
+struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
+{
+       return tty_ldisc_try(tty);
+}
+EXPORT_SYMBOL_GPL(tty_ldisc_ref);
+
+/**
+ *     tty_ldisc_deref         -       free a tty ldisc reference
+ *     @ld: reference to free up
+ *
+ *     Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May
+ *     be called in IRQ context.
+ *
+ *     Locking: takes tty_ldisc_lock
+ */
+
+void tty_ldisc_deref(struct tty_ldisc *ld)
+{
+       put_ldisc(ld);
+}
+EXPORT_SYMBOL_GPL(tty_ldisc_deref);
+
+static inline void tty_ldisc_put(struct tty_ldisc *ld)
+{
+       put_ldisc(ld);
+}
+
+/**
+ *     tty_ldisc_enable        -       allow ldisc use
+ *     @tty: terminal to activate ldisc on
+ *
+ *     Set the TTY_LDISC flag when the line discipline can be called
+ *     again. Do necessary wakeups for existing sleepers. Clear the LDISC
+ *     changing flag to indicate any ldisc change is now over.
+ *
+ *     Note: nobody should set the TTY_LDISC bit except via this function.
+ *     Clearing directly is allowed.
+ */
+
+void tty_ldisc_enable(struct tty_struct *tty)
+{
+       set_bit(TTY_LDISC, &tty->flags);
+       clear_bit(TTY_LDISC_CHANGING, &tty->flags);
+       wake_up(&tty_ldisc_wait);
+}
+
+/**
+ *     tty_ldisc_flush -       flush line discipline queue
+ *     @tty: tty
+ *
+ *     Flush the line discipline queue (if any) for this tty. If there
+ *     is no line discipline active this is a no-op.
+ */
+
+void tty_ldisc_flush(struct tty_struct *tty)
+{
+       struct tty_ldisc *ld = tty_ldisc_ref(tty);
+       if (ld) {
+               if (ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               tty_ldisc_deref(ld);
+       }
+       tty_buffer_flush(tty);
+}
+EXPORT_SYMBOL_GPL(tty_ldisc_flush);
+
+/**
+ *     tty_set_termios_ldisc           -       set ldisc field
+ *     @tty: tty structure
+ *     @num: line discipline number
+ *
+ *     This is probably overkill for real world processors but
+ *     they are not on hot paths so a little discipline won't do
+ *     any harm.
+ *
+ *     Locking: takes termios_mutex
+ */
+
+static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
+{
+       mutex_lock(&tty->termios_mutex);
+       tty->termios->c_line = num;
+       mutex_unlock(&tty->termios_mutex);
+}
+
+/**
+ *     tty_ldisc_open          -       open a line discipline
+ *     @tty: tty we are opening the ldisc on
+ *     @ld: discipline to open
+ *
+ *     A helper opening method. Also a convenient debugging and check
+ *     point.
+ *
+ *     Locking: always called with BTM already held.
+ */
+
+static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
+{
+       WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
+       if (ld->ops->open) {
+               int ret;
+                /* BTM here locks versus a hangup event */
+               WARN_ON(!tty_locked());
+               ret = ld->ops->open(tty);
+               return ret;
+       }
+       return 0;
+}
+
+/**
+ *     tty_ldisc_close         -       close a line discipline
+ *     @tty: tty we are opening the ldisc on
+ *     @ld: discipline to close
+ *
+ *     A helper close method. Also a convenient debugging and check
+ *     point.
+ */
+
+static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
+{
+       WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags));
+       clear_bit(TTY_LDISC_OPEN, &tty->flags);
+       if (ld->ops->close)
+               ld->ops->close(tty);
+}
+
+/**
+ *     tty_ldisc_restore       -       helper for tty ldisc change
+ *     @tty: tty to recover
+ *     @old: previous ldisc
+ *
+ *     Restore the previous line discipline or N_TTY when a line discipline
+ *     change fails due to an open error
+ */
+
+static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
+{
+       char buf[64];
+       struct tty_ldisc *new_ldisc;
+       int r;
+
+       /* There is an outstanding reference here so this is safe */
+       old = tty_ldisc_get(old->ops->num);
+       WARN_ON(IS_ERR(old));
+       tty_ldisc_assign(tty, old);
+       tty_set_termios_ldisc(tty, old->ops->num);
+       if (tty_ldisc_open(tty, old) < 0) {
+               tty_ldisc_put(old);
+               /* This driver is always present */
+               new_ldisc = tty_ldisc_get(N_TTY);
+               if (IS_ERR(new_ldisc))
+                       panic("n_tty: get");
+               tty_ldisc_assign(tty, new_ldisc);
+               tty_set_termios_ldisc(tty, N_TTY);
+               r = tty_ldisc_open(tty, new_ldisc);
+               if (r < 0)
+                       panic("Couldn't open N_TTY ldisc for "
+                             "%s --- error %d.",
+                             tty_name(tty, buf), r);
+       }
+}
+
+/**
+ *     tty_ldisc_halt          -       shut down the line discipline
+ *     @tty: tty device
+ *
+ *     Shut down the line discipline and work queue for this tty device.
+ *     The TTY_LDISC flag being cleared ensures no further references can
+ *     be obtained while the delayed work queue halt ensures that no more
+ *     data is fed to the ldisc.
+ *
+ *     You need to do a 'flush_scheduled_work()' (outside the ldisc_mutex)
+ *     in order to make sure any currently executing ldisc work is also
+ *     flushed.
+ */
+
+static int tty_ldisc_halt(struct tty_struct *tty)
+{
+       clear_bit(TTY_LDISC, &tty->flags);
+       return cancel_delayed_work_sync(&tty->buf.work);
+}
+
+/**
+ *     tty_set_ldisc           -       set line discipline
+ *     @tty: the terminal to set
+ *     @ldisc: the line discipline
+ *
+ *     Set the discipline of a tty line. Must be called from a process
+ *     context. The ldisc change logic has to protect itself against any
+ *     overlapping ldisc change (including on the other end of pty pairs),
+ *     the close of one side of a tty/pty pair, and eventually hangup.
+ *
+ *     Locking: takes tty_ldisc_lock, termios_mutex
+ */
+
+int tty_set_ldisc(struct tty_struct *tty, int ldisc)
+{
+       int retval;
+       struct tty_ldisc *o_ldisc, *new_ldisc;
+       int work, o_work = 0;
+       struct tty_struct *o_tty;
+
+       new_ldisc = tty_ldisc_get(ldisc);
+       if (IS_ERR(new_ldisc))
+               return PTR_ERR(new_ldisc);
+
+       tty_lock();
+       /*
+        *      We need to look at the tty locking here for pty/tty pairs
+        *      when both sides try to change in parallel.
+        */
+
+       o_tty = tty->link;      /* o_tty is the pty side or NULL */
+
+
+       /*
+        *      Check the no-op case
+        */
+
+       if (tty->ldisc->ops->num == ldisc) {
+               tty_unlock();
+               tty_ldisc_put(new_ldisc);
+               return 0;
+       }
+
+       tty_unlock();
+       /*
+        *      Problem: What do we do if this blocks ?
+        *      We could deadlock here
+        */
+
+       tty_wait_until_sent(tty, 0);
+
+       tty_lock();
+       mutex_lock(&tty->ldisc_mutex);
+
+       /*
+        *      We could be midstream of another ldisc change which has
+        *      dropped the lock during processing. If so we need to wait.
+        */
+
+       while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
+               mutex_unlock(&tty->ldisc_mutex);
+               tty_unlock();
+               wait_event(tty_ldisc_wait,
+                       test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
+               tty_lock();
+               mutex_lock(&tty->ldisc_mutex);
+       }
+
+       set_bit(TTY_LDISC_CHANGING, &tty->flags);
+
+       /*
+        *      No more input please, we are switching. The new ldisc
+        *      will update this value in the ldisc open function
+        */
+
+       tty->receive_room = 0;
+
+       o_ldisc = tty->ldisc;
+
+       tty_unlock();
+       /*
+        *      Make sure we don't change while someone holds a
+        *      reference to the line discipline. The TTY_LDISC bit
+        *      prevents anyone taking a reference once it is clear.
+        *      We need the lock to avoid racing reference takers.
+        *
+        *      We must clear the TTY_LDISC bit here to avoid a livelock
+        *      with a userspace app continually trying to use the tty in
+        *      parallel to the change and re-referencing the tty.
+        */
+
+       work = tty_ldisc_halt(tty);
+       if (o_tty)
+               o_work = tty_ldisc_halt(o_tty);
+
+       /*
+        * Wait for ->hangup_work and ->buf.work handlers to terminate.
+        * We must drop the mutex here in case a hangup is also in process.
+        */
+
+       mutex_unlock(&tty->ldisc_mutex);
+
+       flush_scheduled_work();
+
+       tty_lock();
+       mutex_lock(&tty->ldisc_mutex);
+       if (test_bit(TTY_HUPPED, &tty->flags)) {
+               /* We were raced by the hangup method. It will have stomped
+                  the ldisc data and closed the ldisc down */
+               clear_bit(TTY_LDISC_CHANGING, &tty->flags);
+               mutex_unlock(&tty->ldisc_mutex);
+               tty_ldisc_put(new_ldisc);
+               tty_unlock();
+               return -EIO;
+       }
+
+       /* Shutdown the current discipline. */
+       tty_ldisc_close(tty, o_ldisc);
+
+       /* Now set up the new line discipline. */
+       tty_ldisc_assign(tty, new_ldisc);
+       tty_set_termios_ldisc(tty, ldisc);
+
+       retval = tty_ldisc_open(tty, new_ldisc);
+       if (retval < 0) {
+               /* Back to the old one or N_TTY if we can't */
+               tty_ldisc_put(new_ldisc);
+               tty_ldisc_restore(tty, o_ldisc);
+       }
+
+       /* At this point we hold a reference to the new ldisc and a
+          a reference to the old ldisc. If we ended up flipping back
+          to the existing ldisc we have two references to it */
+
+       if (tty->ldisc->ops->num != o_ldisc->ops->num && tty->ops->set_ldisc)
+               tty->ops->set_ldisc(tty);
+
+       tty_ldisc_put(o_ldisc);
+
+       /*
+        *      Allow ldisc referencing to occur again
+        */
+
+       tty_ldisc_enable(tty);
+       if (o_tty)
+               tty_ldisc_enable(o_tty);
+
+       /* Restart the work queue in case no characters kick it off. Safe if
+          already running */
+       if (work)
+               schedule_delayed_work(&tty->buf.work, 1);
+       if (o_work)
+               schedule_delayed_work(&o_tty->buf.work, 1);
+       mutex_unlock(&tty->ldisc_mutex);
+       tty_unlock();
+       return retval;
+}
+
+/**
+ *     tty_reset_termios       -       reset terminal state
+ *     @tty: tty to reset
+ *
+ *     Restore a terminal to the driver default state.
+ */
+
+static void tty_reset_termios(struct tty_struct *tty)
+{
+       mutex_lock(&tty->termios_mutex);
+       *tty->termios = tty->driver->init_termios;
+       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
+       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+       mutex_unlock(&tty->termios_mutex);
+}
+
+
+/**
+ *     tty_ldisc_reinit        -       reinitialise the tty ldisc
+ *     @tty: tty to reinit
+ *     @ldisc: line discipline to reinitialize
+ *
+ *     Switch the tty to a line discipline and leave the ldisc
+ *     state closed
+ */
+
+static void tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
+{
+       struct tty_ldisc *ld;
+
+       tty_ldisc_close(tty, tty->ldisc);
+       tty_ldisc_put(tty->ldisc);
+       tty->ldisc = NULL;
+       /*
+        *      Switch the line discipline back
+        */
+       ld = tty_ldisc_get(ldisc);
+       BUG_ON(IS_ERR(ld));
+       tty_ldisc_assign(tty, ld);
+       tty_set_termios_ldisc(tty, ldisc);
+}
+
+/**
+ *     tty_ldisc_hangup                -       hangup ldisc reset
+ *     @tty: tty being hung up
+ *
+ *     Some tty devices reset their termios when they receive a hangup
+ *     event. In that situation we must also switch back to N_TTY properly
+ *     before we reset the termios data.
+ *
+ *     Locking: We can take the ldisc mutex as the rest of the code is
+ *     careful to allow for this.
+ *
+ *     In the pty pair case this occurs in the close() path of the
+ *     tty itself so we must be careful about locking rules.
+ */
+
+void tty_ldisc_hangup(struct tty_struct *tty)
+{
+       struct tty_ldisc *ld;
+       int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;
+       int err = 0;
+
+       /*
+        * FIXME! What are the locking issues here? This may me overdoing
+        * things... This question is especially important now that we've
+        * removed the irqlock.
+        */
+       ld = tty_ldisc_ref(tty);
+       if (ld != NULL) {
+               /* We may have no line discipline at this point */
+               if (ld->ops->flush_buffer)
+                       ld->ops->flush_buffer(tty);
+               tty_driver_flush_buffer(tty);
+               if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
+                   ld->ops->write_wakeup)
+                       ld->ops->write_wakeup(tty);
+               if (ld->ops->hangup)
+                       ld->ops->hangup(tty);
+               tty_ldisc_deref(ld);
+       }
+       /*
+        * FIXME: Once we trust the LDISC code better we can wait here for
+        * ldisc completion and fix the driver call race
+        */
+       wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
+       wake_up_interruptible_poll(&tty->read_wait, POLLIN);
+       /*
+        * Shutdown the current line discipline, and reset it to
+        * N_TTY if need be.
+        *
+        * Avoid racing set_ldisc or tty_ldisc_release
+        */
+       mutex_lock(&tty->ldisc_mutex);
+
+       /*
+        * this is like tty_ldisc_halt, but we need to give up
+        * the BTM before calling cancel_delayed_work_sync,
+        * which may need to wait for another function taking the BTM
+        */
+       clear_bit(TTY_LDISC, &tty->flags);
+       tty_unlock();
+       cancel_delayed_work_sync(&tty->buf.work);
+       mutex_unlock(&tty->ldisc_mutex);
+
+       tty_lock();
+       mutex_lock(&tty->ldisc_mutex);
+
+       /* At this point we have a closed ldisc and we want to
+          reopen it. We could defer this to the next open but
+          it means auditing a lot of other paths so this is
+          a FIXME */
+       if (tty->ldisc) {       /* Not yet closed */
+               if (reset == 0) {
+                       tty_ldisc_reinit(tty, tty->termios->c_line);
+                       err = tty_ldisc_open(tty, tty->ldisc);
+               }
+               /* If the re-open fails or we reset then go to N_TTY. The
+                  N_TTY open cannot fail */
+               if (reset || err) {
+                       tty_ldisc_reinit(tty, N_TTY);
+                       WARN_ON(tty_ldisc_open(tty, tty->ldisc));
+               }
+               tty_ldisc_enable(tty);
+       }
+       mutex_unlock(&tty->ldisc_mutex);
+       if (reset)
+               tty_reset_termios(tty);
+}
+
+/**
+ *     tty_ldisc_setup                 -       open line discipline
+ *     @tty: tty being shut down
+ *     @o_tty: pair tty for pty/tty pairs
+ *
+ *     Called during the initial open of a tty/pty pair in order to set up the
+ *     line disciplines and bind them to the tty. This has no locking issues
+ *     as the device isn't yet active.
+ */
+
+int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
+{
+       struct tty_ldisc *ld = tty->ldisc;
+       int retval;
+
+       retval = tty_ldisc_open(tty, ld);
+       if (retval)
+               return retval;
+
+       if (o_tty) {
+               retval = tty_ldisc_open(o_tty, o_tty->ldisc);
+               if (retval) {
+                       tty_ldisc_close(tty, ld);
+                       return retval;
+               }
+               tty_ldisc_enable(o_tty);
+       }
+       tty_ldisc_enable(tty);
+       return 0;
+}
+/**
+ *     tty_ldisc_release               -       release line discipline
+ *     @tty: tty being shut down
+ *     @o_tty: pair tty for pty/tty pairs
+ *
+ *     Called during the final close of a tty/pty pair in order to shut down
+ *     the line discpline layer. On exit the ldisc assigned is N_TTY and the
+ *     ldisc has not been opened.
+ */
+
+void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
+{
+       /*
+        * Prevent flush_to_ldisc() from rescheduling the work for later.  Then
+        * kill any delayed work. As this is the final close it does not
+        * race with the set_ldisc code path.
+        */
+
+       tty_unlock();
+       tty_ldisc_halt(tty);
+       flush_scheduled_work();
+       tty_lock();
+
+       mutex_lock(&tty->ldisc_mutex);
+       /*
+        * Now kill off the ldisc
+        */
+       tty_ldisc_close(tty, tty->ldisc);
+       tty_ldisc_put(tty->ldisc);
+       /* Force an oops if we mess this up */
+       tty->ldisc = NULL;
+
+       /* Ensure the next open requests the N_TTY ldisc */
+       tty_set_termios_ldisc(tty, N_TTY);
+       mutex_unlock(&tty->ldisc_mutex);
+
+       /* This will need doing differently if we need to lock */
+       if (o_tty)
+               tty_ldisc_release(o_tty, NULL);
+
+       /* And the memory resources remaining (buffers, termios) will be
+          disposed of when the kref hits zero */
+}
+
+/**
+ *     tty_ldisc_init          -       ldisc setup for new tty
+ *     @tty: tty being allocated
+ *
+ *     Set up the line discipline objects for a newly allocated tty. Note that
+ *     the tty structure is not completely set up when this call is made.
+ */
+
+void tty_ldisc_init(struct tty_struct *tty)
+{
+       struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
+       if (IS_ERR(ld))
+               panic("n_tty: init_tty");
+       tty_ldisc_assign(tty, ld);
+}
+
+void tty_ldisc_begin(void)
+{
+       /* Setup the default TTY line discipline. */
+       (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
+}
diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c
new file mode 100644 (file)
index 0000000..1336975
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * drivers/char/tty_lock.c
+ */
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+#include <linux/semaphore.h>
+#include <linux/sched.h>
+
+/*
+ * The 'big tty mutex'
+ *
+ * This mutex is taken and released by tty_lock() and tty_unlock(),
+ * replacing the older big kernel lock.
+ * It can no longer be taken recursively, and does not get
+ * released implicitly while sleeping.
+ *
+ * Don't use in new code.
+ */
+static DEFINE_MUTEX(big_tty_mutex);
+struct task_struct *__big_tty_mutex_owner;
+EXPORT_SYMBOL_GPL(__big_tty_mutex_owner);
+
+/*
+ * Getting the big tty mutex.
+ */
+void __lockfunc tty_lock(void)
+{
+       struct task_struct *task = current;
+
+       WARN_ON(__big_tty_mutex_owner == task);
+
+       mutex_lock(&big_tty_mutex);
+       __big_tty_mutex_owner = task;
+}
+EXPORT_SYMBOL(tty_lock);
+
+void __lockfunc tty_unlock(void)
+{
+       struct task_struct *task = current;
+
+       WARN_ON(__big_tty_mutex_owner != task);
+       __big_tty_mutex_owner = NULL;
+
+       mutex_unlock(&big_tty_mutex);
+}
+EXPORT_SYMBOL(tty_unlock);
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
new file mode 100644 (file)
index 0000000..33d37d2
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ * Tty port functions
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+void tty_port_init(struct tty_port *port)
+{
+       memset(port, 0, sizeof(*port));
+       init_waitqueue_head(&port->open_wait);
+       init_waitqueue_head(&port->close_wait);
+       init_waitqueue_head(&port->delta_msr_wait);
+       mutex_init(&port->mutex);
+       mutex_init(&port->buf_mutex);
+       spin_lock_init(&port->lock);
+       port->close_delay = (50 * HZ) / 100;
+       port->closing_wait = (3000 * HZ) / 100;
+       kref_init(&port->kref);
+}
+EXPORT_SYMBOL(tty_port_init);
+
+int tty_port_alloc_xmit_buf(struct tty_port *port)
+{
+       /* We may sleep in get_zeroed_page() */
+       mutex_lock(&port->buf_mutex);
+       if (port->xmit_buf == NULL)
+               port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL);
+       mutex_unlock(&port->buf_mutex);
+       if (port->xmit_buf == NULL)
+               return -ENOMEM;
+       return 0;
+}
+EXPORT_SYMBOL(tty_port_alloc_xmit_buf);
+
+void tty_port_free_xmit_buf(struct tty_port *port)
+{
+       mutex_lock(&port->buf_mutex);
+       if (port->xmit_buf != NULL) {
+               free_page((unsigned long)port->xmit_buf);
+               port->xmit_buf = NULL;
+       }
+       mutex_unlock(&port->buf_mutex);
+}
+EXPORT_SYMBOL(tty_port_free_xmit_buf);
+
+static void tty_port_destructor(struct kref *kref)
+{
+       struct tty_port *port = container_of(kref, struct tty_port, kref);
+       if (port->xmit_buf)
+               free_page((unsigned long)port->xmit_buf);
+       if (port->ops->destruct)
+               port->ops->destruct(port);
+       else
+               kfree(port);
+}
+
+void tty_port_put(struct tty_port *port)
+{
+       if (port)
+               kref_put(&port->kref, tty_port_destructor);
+}
+EXPORT_SYMBOL(tty_port_put);
+
+/**
+ *     tty_port_tty_get        -       get a tty reference
+ *     @port: tty port
+ *
+ *     Return a refcount protected tty instance or NULL if the port is not
+ *     associated with a tty (eg due to close or hangup)
+ */
+
+struct tty_struct *tty_port_tty_get(struct tty_port *port)
+{
+       unsigned long flags;
+       struct tty_struct *tty;
+
+       spin_lock_irqsave(&port->lock, flags);
+       tty = tty_kref_get(port->tty);
+       spin_unlock_irqrestore(&port->lock, flags);
+       return tty;
+}
+EXPORT_SYMBOL(tty_port_tty_get);
+
+/**
+ *     tty_port_tty_set        -       set the tty of a port
+ *     @port: tty port
+ *     @tty: the tty
+ *
+ *     Associate the port and tty pair. Manages any internal refcounts.
+ *     Pass NULL to deassociate a port
+ */
+
+void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (port->tty)
+               tty_kref_put(port->tty);
+       port->tty = tty_kref_get(tty);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+EXPORT_SYMBOL(tty_port_tty_set);
+
+static void tty_port_shutdown(struct tty_port *port)
+{
+       mutex_lock(&port->mutex);
+       if (port->ops->shutdown && !port->console &&
+               test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
+                       port->ops->shutdown(port);
+       mutex_unlock(&port->mutex);
+}
+
+/**
+ *     tty_port_hangup         -       hangup helper
+ *     @port: tty port
+ *
+ *     Perform port level tty hangup flag and count changes. Drop the tty
+ *     reference.
+ */
+
+void tty_port_hangup(struct tty_port *port)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       port->count = 0;
+       port->flags &= ~ASYNC_NORMAL_ACTIVE;
+       if (port->tty) {
+               set_bit(TTY_IO_ERROR, &port->tty->flags);
+               tty_kref_put(port->tty);
+       }
+       port->tty = NULL;
+       spin_unlock_irqrestore(&port->lock, flags);
+       wake_up_interruptible(&port->open_wait);
+       wake_up_interruptible(&port->delta_msr_wait);
+       tty_port_shutdown(port);
+}
+EXPORT_SYMBOL(tty_port_hangup);
+
+/**
+ *     tty_port_carrier_raised -       carrier raised check
+ *     @port: tty port
+ *
+ *     Wrapper for the carrier detect logic. For the moment this is used
+ *     to hide some internal details. This will eventually become entirely
+ *     internal to the tty port.
+ */
+
+int tty_port_carrier_raised(struct tty_port *port)
+{
+       if (port->ops->carrier_raised == NULL)
+               return 1;
+       return port->ops->carrier_raised(port);
+}
+EXPORT_SYMBOL(tty_port_carrier_raised);
+
+/**
+ *     tty_port_raise_dtr_rts  -       Raise DTR/RTS
+ *     @port: tty port
+ *
+ *     Wrapper for the DTR/RTS raise logic. For the moment this is used
+ *     to hide some internal details. This will eventually become entirely
+ *     internal to the tty port.
+ */
+
+void tty_port_raise_dtr_rts(struct tty_port *port)
+{
+       if (port->ops->dtr_rts)
+               port->ops->dtr_rts(port, 1);
+}
+EXPORT_SYMBOL(tty_port_raise_dtr_rts);
+
+/**
+ *     tty_port_lower_dtr_rts  -       Lower DTR/RTS
+ *     @port: tty port
+ *
+ *     Wrapper for the DTR/RTS raise logic. For the moment this is used
+ *     to hide some internal details. This will eventually become entirely
+ *     internal to the tty port.
+ */
+
+void tty_port_lower_dtr_rts(struct tty_port *port)
+{
+       if (port->ops->dtr_rts)
+               port->ops->dtr_rts(port, 0);
+}
+EXPORT_SYMBOL(tty_port_lower_dtr_rts);
+
+/**
+ *     tty_port_block_til_ready        -       Waiting logic for tty open
+ *     @port: the tty port being opened
+ *     @tty: the tty device being bound
+ *     @filp: the file pointer of the opener
+ *
+ *     Implement the core POSIX/SuS tty behaviour when opening a tty device.
+ *     Handles:
+ *             - hangup (both before and during)
+ *             - non blocking open
+ *             - rts/dtr/dcd
+ *             - signals
+ *             - port flags and counts
+ *
+ *     The passed tty_port must implement the carrier_raised method if it can
+ *     do carrier detect and the dtr_rts method if it supports software
+ *     management of these lines. Note that the dtr/rts raise is done each
+ *     iteration as a hangup may have previously dropped them while we wait.
+ */
+
+int tty_port_block_til_ready(struct tty_port *port,
+                               struct tty_struct *tty, struct file *filp)
+{
+       int do_clocal = 0, retval;
+       unsigned long flags;
+       DEFINE_WAIT(wait);
+       int cd;
+
+       /* block if port is in the process of being closed */
+       if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
+               wait_event_interruptible_tty(port->close_wait,
+                               !(port->flags & ASYNC_CLOSING));
+               if (port->flags & ASYNC_HUP_NOTIFY)
+                       return -EAGAIN;
+               else
+                       return -ERESTARTSYS;
+       }
+
+       /* if non-blocking mode is set we can pass directly to open unless
+          the port has just hung up or is in another error state */
+       if (tty->flags & (1 << TTY_IO_ERROR)) {
+               port->flags |= ASYNC_NORMAL_ACTIVE;
+               return 0;
+       }
+       if (filp->f_flags & O_NONBLOCK) {
+               /* Indicate we are open */
+               if (tty->termios->c_cflag & CBAUD)
+                       tty_port_raise_dtr_rts(port);
+               port->flags |= ASYNC_NORMAL_ACTIVE;
+               return 0;
+       }
+
+       if (C_CLOCAL(tty))
+               do_clocal = 1;
+
+       /* Block waiting until we can proceed. We may need to wait for the
+          carrier, but we must also wait for any close that is in progress
+          before the next open may complete */
+
+       retval = 0;
+
+       /* The port lock protects the port counts */
+       spin_lock_irqsave(&port->lock, flags);
+       if (!tty_hung_up_p(filp))
+               port->count--;
+       port->blocked_open++;
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       while (1) {
+               /* Indicate we are open */
+               if (tty->termios->c_cflag & CBAUD)
+                       tty_port_raise_dtr_rts(port);
+
+               prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
+               /* Check for a hangup or uninitialised port.
+                                                       Return accordingly */
+               if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
+                       if (port->flags & ASYNC_HUP_NOTIFY)
+                               retval = -EAGAIN;
+                       else
+                               retval = -ERESTARTSYS;
+                       break;
+               }
+               /* Probe the carrier. For devices with no carrier detect this
+                  will always return true */
+               cd = tty_port_carrier_raised(port);
+               if (!(port->flags & ASYNC_CLOSING) &&
+                               (do_clocal || cd))
+                       break;
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+               tty_unlock();
+               schedule();
+               tty_lock();
+       }
+       finish_wait(&port->open_wait, &wait);
+
+       /* Update counts. A parallel hangup will have set count to zero and
+          we must not mess that up further */
+       spin_lock_irqsave(&port->lock, flags);
+       if (!tty_hung_up_p(filp))
+               port->count++;
+       port->blocked_open--;
+       if (retval == 0)
+               port->flags |= ASYNC_NORMAL_ACTIVE;
+       spin_unlock_irqrestore(&port->lock, flags);
+       return retval;
+}
+EXPORT_SYMBOL(tty_port_block_til_ready);
+
+int tty_port_close_start(struct tty_port *port,
+                               struct tty_struct *tty, struct file *filp)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       if (tty_hung_up_p(filp)) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               return 0;
+       }
+
+       if (tty->count == 1 && port->count != 1) {
+               printk(KERN_WARNING
+                   "tty_port_close_start: tty->count = 1 port count = %d.\n",
+                                                               port->count);
+               port->count = 1;
+       }
+       if (--port->count < 0) {
+               printk(KERN_WARNING "tty_port_close_start: count = %d\n",
+                                                               port->count);
+               port->count = 0;
+       }
+
+       if (port->count) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               if (port->ops->drop)
+                       port->ops->drop(port);
+               return 0;
+       }
+       set_bit(ASYNCB_CLOSING, &port->flags);
+       tty->closing = 1;
+       spin_unlock_irqrestore(&port->lock, flags);
+       /* Don't block on a stalled port, just pull the chain */
+       if (tty->flow_stopped)
+               tty_driver_flush_buffer(tty);
+       if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
+                       port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, port->closing_wait);
+       if (port->drain_delay) {
+               unsigned int bps = tty_get_baud_rate(tty);
+               long timeout;
+
+               if (bps > 1200)
+                       timeout = max_t(long,
+                               (HZ * 10 * port->drain_delay) / bps, HZ / 10);
+               else
+                       timeout = 2 * HZ;
+               schedule_timeout_interruptible(timeout);
+       }
+       /* Flush the ldisc buffering */
+       tty_ldisc_flush(tty);
+
+       /* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
+          hang up the line */
+       if (tty->termios->c_cflag & HUPCL)
+               tty_port_lower_dtr_rts(port);
+
+       /* Don't call port->drop for the last reference. Callers will want
+          to drop the last active reference in ->shutdown() or the tty
+          shutdown path */
+       return 1;
+}
+EXPORT_SYMBOL(tty_port_close_start);
+
+void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       tty->closing = 0;
+
+       if (port->blocked_open) {
+               spin_unlock_irqrestore(&port->lock, flags);
+               if (port->close_delay) {
+                       msleep_interruptible(
+                               jiffies_to_msecs(port->close_delay));
+               }
+               spin_lock_irqsave(&port->lock, flags);
+               wake_up_interruptible(&port->open_wait);
+       }
+       port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+       wake_up_interruptible(&port->close_wait);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+EXPORT_SYMBOL(tty_port_close_end);
+
+void tty_port_close(struct tty_port *port, struct tty_struct *tty,
+                                                       struct file *filp)
+{
+       if (tty_port_close_start(port, tty, filp) == 0)
+               return;
+       tty_port_shutdown(port);
+       set_bit(TTY_IO_ERROR, &tty->flags);
+       tty_port_close_end(port, tty);
+       tty_port_tty_set(port, NULL);
+}
+EXPORT_SYMBOL(tty_port_close);
+
+int tty_port_open(struct tty_port *port, struct tty_struct *tty,
+                                                       struct file *filp)
+{
+       spin_lock_irq(&port->lock);
+       if (!tty_hung_up_p(filp))
+               ++port->count;
+       spin_unlock_irq(&port->lock);
+       tty_port_tty_set(port, tty);
+
+       /*
+        * Do the device-specific open only if the hardware isn't
+        * already initialized. Serialize open and shutdown using the
+        * port mutex.
+        */
+
+       mutex_lock(&port->mutex);
+
+       if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+               clear_bit(TTY_IO_ERROR, &tty->flags);
+               if (port->ops->activate) {
+                       int retval = port->ops->activate(port, tty);
+                       if (retval) {
+                               mutex_unlock(&port->mutex);
+                               return retval;
+                       }
+               }
+               set_bit(ASYNCB_INITIALIZED, &port->flags);
+       }
+       mutex_unlock(&port->mutex);
+       return tty_port_block_til_ready(port, tty, filp);
+}
+
+EXPORT_SYMBOL(tty_port_open);
diff --git a/drivers/tty/vt/.gitignore b/drivers/tty/vt/.gitignore
new file mode 100644 (file)
index 0000000..83683a2
--- /dev/null
@@ -0,0 +1,2 @@
+consolemap_deftbl.c
+defkeymap.c
diff --git a/drivers/tty/vt/Makefile b/drivers/tty/vt/Makefile
new file mode 100644 (file)
index 0000000..14a51c9
--- /dev/null
@@ -0,0 +1,34 @@
+#
+# This file contains the font map for the default (hardware) font
+#
+FONTMAPFILE = cp437.uni
+
+obj-$(CONFIG_VT)                       += vt_ioctl.o vc_screen.o \
+                                          selection.o keyboard.o
+obj-$(CONFIG_CONSOLE_TRANSLATIONS)     += consolemap.o consolemap_deftbl.o
+obj-$(CONFIG_HW_CONSOLE)               += vt.o defkeymap.o
+
+# Files generated that shall be removed upon make clean
+clean-files := consolemap_deftbl.c defkeymap.c
+
+quiet_cmd_conmk = CONMK   $@
+      cmd_conmk = scripts/conmakehash $< > $@
+
+$(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE)
+       $(call cmd,conmk)
+
+$(obj)/defkeymap.o:  $(obj)/defkeymap.c
+
+# Uncomment if you're changing the keymap and have an appropriate
+# loadkeys version for the map. By default, we'll use the shipped
+# versions.
+# GENERATE_KEYMAP := 1
+
+ifdef GENERATE_KEYMAP
+
+$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map
+       loadkeys --mktable $< > $@.tmp
+       sed -e 's/^static *//' $@.tmp > $@
+       rm $@.tmp
+
+endif
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
new file mode 100644 (file)
index 0000000..45d3e80
--- /dev/null
@@ -0,0 +1,745 @@
+/*
+ * consolemap.c
+ *
+ * Mapping from internal code (such as Latin-1 or Unicode or IBM PC code)
+ * to font positions.
+ *
+ * aeb, 950210
+ *
+ * Support for multiple unimaps by Jakub Jelinek <jj@ultra.linux.cz>, July 1998
+ *
+ * Fix bug in inverse translation. Stanislav Voronyi <stas@cnti.uanet.kharkov.ua>, Dec 1998
+ */
+
+#include <linux/module.h>
+#include <linux/kd.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <asm/uaccess.h>
+#include <linux/consolemap.h>
+#include <linux/vt_kern.h>
+
+static unsigned short translations[][256] = {
+  /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
+  {
+    0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+    0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
+    0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+    0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
+    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+    0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+    0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+    0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
+    0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+    0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
+    0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+    0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
+    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
+    0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
+    0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
+    0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+    0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
+    0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
+    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+    0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
+    0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
+  }, 
+  /* VT100 graphics mapped to Unicode */
+  {
+    0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+    0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
+    0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+    0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
+    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+    0x0028, 0x0029, 0x002a, 0x2192, 0x2190, 0x2191, 0x2193, 0x002f,
+    0x2588, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x00a0,
+    0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1,
+    0x2591, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba,
+    0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c,
+    0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7, 0x007f,
+    0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+    0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
+    0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+    0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
+    0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
+    0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+    0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
+    0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+    0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
+    0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+    0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
+    0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
+    0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+    0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+    0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
+    0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
+  },
+  /* IBM Codepage 437 mapped to Unicode */
+  {
+    0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 
+    0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
+    0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
+    0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
+    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+    0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+    0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+    0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
+    0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
+    0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
+    0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
+    0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
+    0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
+    0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
+    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
+    0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
+    0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
+    0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
+    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
+    0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
+    0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
+    0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
+    0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
+    0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
+  }, 
+  /* User mapping -- default to codes for direct font mapping */
+  {
+    0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007,
+    0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f,
+    0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017,
+    0xf018, 0xf019, 0xf01a, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f,
+    0xf020, 0xf021, 0xf022, 0xf023, 0xf024, 0xf025, 0xf026, 0xf027,
+    0xf028, 0xf029, 0xf02a, 0xf02b, 0xf02c, 0xf02d, 0xf02e, 0xf02f,
+    0xf030, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
+    0xf038, 0xf039, 0xf03a, 0xf03b, 0xf03c, 0xf03d, 0xf03e, 0xf03f,
+    0xf040, 0xf041, 0xf042, 0xf043, 0xf044, 0xf045, 0xf046, 0xf047,
+    0xf048, 0xf049, 0xf04a, 0xf04b, 0xf04c, 0xf04d, 0xf04e, 0xf04f,
+    0xf050, 0xf051, 0xf052, 0xf053, 0xf054, 0xf055, 0xf056, 0xf057,
+    0xf058, 0xf059, 0xf05a, 0xf05b, 0xf05c, 0xf05d, 0xf05e, 0xf05f,
+    0xf060, 0xf061, 0xf062, 0xf063, 0xf064, 0xf065, 0xf066, 0xf067,
+    0xf068, 0xf069, 0xf06a, 0xf06b, 0xf06c, 0xf06d, 0xf06e, 0xf06f,
+    0xf070, 0xf071, 0xf072, 0xf073, 0xf074, 0xf075, 0xf076, 0xf077,
+    0xf078, 0xf079, 0xf07a, 0xf07b, 0xf07c, 0xf07d, 0xf07e, 0xf07f,
+    0xf080, 0xf081, 0xf082, 0xf083, 0xf084, 0xf085, 0xf086, 0xf087,
+    0xf088, 0xf089, 0xf08a, 0xf08b, 0xf08c, 0xf08d, 0xf08e, 0xf08f,
+    0xf090, 0xf091, 0xf092, 0xf093, 0xf094, 0xf095, 0xf096, 0xf097,
+    0xf098, 0xf099, 0xf09a, 0xf09b, 0xf09c, 0xf09d, 0xf09e, 0xf09f,
+    0xf0a0, 0xf0a1, 0xf0a2, 0xf0a3, 0xf0a4, 0xf0a5, 0xf0a6, 0xf0a7,
+    0xf0a8, 0xf0a9, 0xf0aa, 0xf0ab, 0xf0ac, 0xf0ad, 0xf0ae, 0xf0af,
+    0xf0b0, 0xf0b1, 0xf0b2, 0xf0b3, 0xf0b4, 0xf0b5, 0xf0b6, 0xf0b7,
+    0xf0b8, 0xf0b9, 0xf0ba, 0xf0bb, 0xf0bc, 0xf0bd, 0xf0be, 0xf0bf,
+    0xf0c0, 0xf0c1, 0xf0c2, 0xf0c3, 0xf0c4, 0xf0c5, 0xf0c6, 0xf0c7,
+    0xf0c8, 0xf0c9, 0xf0ca, 0xf0cb, 0xf0cc, 0xf0cd, 0xf0ce, 0xf0cf,
+    0xf0d0, 0xf0d1, 0xf0d2, 0xf0d3, 0xf0d4, 0xf0d5, 0xf0d6, 0xf0d7,
+    0xf0d8, 0xf0d9, 0xf0da, 0xf0db, 0xf0dc, 0xf0dd, 0xf0de, 0xf0df,
+    0xf0e0, 0xf0e1, 0xf0e2, 0xf0e3, 0xf0e4, 0xf0e5, 0xf0e6, 0xf0e7,
+    0xf0e8, 0xf0e9, 0xf0ea, 0xf0eb, 0xf0ec, 0xf0ed, 0xf0ee, 0xf0ef,
+    0xf0f0, 0xf0f1, 0xf0f2, 0xf0f3, 0xf0f4, 0xf0f5, 0xf0f6, 0xf0f7,
+    0xf0f8, 0xf0f9, 0xf0fa, 0xf0fb, 0xf0fc, 0xf0fd, 0xf0fe, 0xf0ff
+  }
+};
+
+/* The standard kernel character-to-font mappings are not invertible
+   -- this is just a best effort. */
+
+#define MAX_GLYPH 512          /* Max possible glyph value */
+
+static int inv_translate[MAX_NR_CONSOLES];
+
+struct uni_pagedir {
+       u16             **uni_pgdir[32];
+       unsigned long   refcount;
+       unsigned long   sum;
+       unsigned char   *inverse_translations[4];
+       u16             *inverse_trans_unicode;
+       int             readonly;
+};
+
+static struct uni_pagedir *dflt;
+
+static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i)
+{
+       int j, glyph;
+       unsigned short *t = translations[i];
+       unsigned char *q;
+       
+       if (!p) return;
+       q = p->inverse_translations[i];
+
+       if (!q) {
+               q = p->inverse_translations[i] = (unsigned char *) 
+                       kmalloc(MAX_GLYPH, GFP_KERNEL);
+               if (!q) return;
+       }
+       memset(q, 0, MAX_GLYPH);
+
+       for (j = 0; j < E_TABSZ; j++) {
+               glyph = conv_uni_to_pc(conp, t[j]);
+               if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) {
+                       /* prefer '-' above SHY etc. */
+                       q[glyph] = j;
+               }
+       }
+}
+
+static void set_inverse_trans_unicode(struct vc_data *conp,
+                                     struct uni_pagedir *p)
+{
+       int i, j, k, glyph;
+       u16 **p1, *p2;
+       u16 *q;
+
+       if (!p) return;
+       q = p->inverse_trans_unicode;
+       if (!q) {
+               q = p->inverse_trans_unicode =
+                       kmalloc(MAX_GLYPH * sizeof(u16), GFP_KERNEL);
+               if (!q)
+                       return;
+       }
+       memset(q, 0, MAX_GLYPH * sizeof(u16));
+
+       for (i = 0; i < 32; i++) {
+               p1 = p->uni_pgdir[i];
+               if (!p1)
+                       continue;
+               for (j = 0; j < 32; j++) {
+                       p2 = p1[j];
+                       if (!p2)
+                               continue;
+                       for (k = 0; k < 64; k++) {
+                               glyph = p2[k];
+                               if (glyph >= 0 && glyph < MAX_GLYPH
+                                              && q[glyph] < 32)
+                                       q[glyph] = (i << 11) + (j << 6) + k;
+                       }
+               }
+       }
+}
+
+unsigned short *set_translate(int m, struct vc_data *vc)
+{
+       inv_translate[vc->vc_num] = m;
+       return translations[m];
+}
+
+/*
+ * Inverse translation is impossible for several reasons:
+ * 1. The font<->character maps are not 1-1.
+ * 2. The text may have been written while a different translation map
+ *    was active.
+ * Still, it is now possible to a certain extent to cut and paste non-ASCII.
+ */
+u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
+{
+       struct uni_pagedir *p;
+       int m;
+       if (glyph < 0 || glyph >= MAX_GLYPH)
+               return 0;
+       else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
+               return glyph;
+       else if (use_unicode) {
+               if (!p->inverse_trans_unicode)
+                       return glyph;
+               else
+                       return p->inverse_trans_unicode[glyph];
+       } else {
+               m = inv_translate[conp->vc_num];
+               if (!p->inverse_translations[m])
+                       return glyph;
+               else
+                       return p->inverse_translations[m][glyph];
+       }
+}
+EXPORT_SYMBOL_GPL(inverse_translate);
+
+static void update_user_maps(void)
+{
+       int i;
+       struct uni_pagedir *p, *q = NULL;
+       
+       for (i = 0; i < MAX_NR_CONSOLES; i++) {
+               if (!vc_cons_allocated(i))
+                       continue;
+               p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+               if (p && p != q) {
+                       set_inverse_transl(vc_cons[i].d, p, USER_MAP);
+                       set_inverse_trans_unicode(vc_cons[i].d, p);
+                       q = p;
+               }
+       }
+}
+
+/*
+ * Load customizable translation table
+ * arg points to a 256 byte translation table.
+ *
+ * The "old" variants are for translation directly to font (using the
+ * 0xf000-0xf0ff "transparent" Unicodes) whereas the "new" variants set
+ * Unicodes explicitly.
+ */
+int con_set_trans_old(unsigned char __user * arg)
+{
+       int i;
+       unsigned short *p = translations[USER_MAP];
+
+       if (!access_ok(VERIFY_READ, arg, E_TABSZ))
+               return -EFAULT;
+
+       for (i=0; i<E_TABSZ ; i++) {
+               unsigned char uc;
+               __get_user(uc, arg+i);
+               p[i] = UNI_DIRECT_BASE | uc;
+       }
+
+       update_user_maps();
+       return 0;
+}
+
+int con_get_trans_old(unsigned char __user * arg)
+{
+       int i, ch;
+       unsigned short *p = translations[USER_MAP];
+
+       if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
+               return -EFAULT;
+
+       for (i=0; i<E_TABSZ ; i++)
+         {
+           ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
+           __put_user((ch & ~0xff) ? 0 : ch, arg+i);
+         }
+       return 0;
+}
+
+int con_set_trans_new(ushort __user * arg)
+{
+       int i;
+       unsigned short *p = translations[USER_MAP];
+
+       if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
+               return -EFAULT;
+
+       for (i=0; i<E_TABSZ ; i++) {
+               unsigned short us;
+               __get_user(us, arg+i);
+               p[i] = us;
+       }
+
+       update_user_maps();
+       return 0;
+}
+
+int con_get_trans_new(ushort __user * arg)
+{
+       int i;
+       unsigned short *p = translations[USER_MAP];
+
+       if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
+               return -EFAULT;
+
+       for (i=0; i<E_TABSZ ; i++)
+         __put_user(p[i], arg+i);
+       
+       return 0;
+}
+
+/*
+ * Unicode -> current font conversion 
+ *
+ * A font has at most 512 chars, usually 256.
+ * But one font position may represent several Unicode chars.
+ * A hashtable is somewhat of a pain to deal with, so use a
+ * "paged table" instead.  Simulation has shown the memory cost of
+ * this 3-level paged table scheme to be comparable to a hash table.
+ */
+
+extern u8 dfont_unicount[];    /* Defined in console_defmap.c */
+extern u16 dfont_unitable[];
+
+static void con_release_unimap(struct uni_pagedir *p)
+{
+       u16 **p1;
+       int i, j;
+
+       if (p == dflt) dflt = NULL;  
+       for (i = 0; i < 32; i++) {
+               if ((p1 = p->uni_pgdir[i]) != NULL) {
+                       for (j = 0; j < 32; j++)
+                               kfree(p1[j]);
+                       kfree(p1);
+               }
+               p->uni_pgdir[i] = NULL;
+       }
+       for (i = 0; i < 4; i++) {
+               kfree(p->inverse_translations[i]);
+               p->inverse_translations[i] = NULL;
+       }
+       if (p->inverse_trans_unicode) {
+               kfree(p->inverse_trans_unicode);
+               p->inverse_trans_unicode = NULL;
+       }
+}
+
+void con_free_unimap(struct vc_data *vc)
+{
+       struct uni_pagedir *p;
+
+       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+       if (!p)
+               return;
+       *vc->vc_uni_pagedir_loc = 0;
+       if (--p->refcount)
+               return;
+       con_release_unimap(p);
+       kfree(p);
+}
+  
+static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
+{
+       int i, j, k;
+       struct uni_pagedir *q;
+       
+       for (i = 0; i < MAX_NR_CONSOLES; i++) {
+               if (!vc_cons_allocated(i))
+                       continue;
+               q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
+               if (!q || q == p || q->sum != p->sum)
+                       continue;
+               for (j = 0; j < 32; j++) {
+                       u16 **p1, **q1;
+                       p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j];
+                       if (!p1 && !q1)
+                               continue;
+                       if (!p1 || !q1)
+                               break;
+                       for (k = 0; k < 32; k++) {
+                               if (!p1[k] && !q1[k])
+                                       continue;
+                               if (!p1[k] || !q1[k])
+                                       break;
+                               if (memcmp(p1[k], q1[k], 64*sizeof(u16)))
+                                       break;
+                       }
+                       if (k < 32)
+                               break;
+               }
+               if (j == 32) {
+                       q->refcount++;
+                       *conp->vc_uni_pagedir_loc = (unsigned long)q;
+                       con_release_unimap(p);
+                       kfree(p);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+static int
+con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
+{
+       int i, n;
+       u16 **p1, *p2;
+
+       if (!(p1 = p->uni_pgdir[n = unicode >> 11])) {
+               p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL);
+               if (!p1) return -ENOMEM;
+               for (i = 0; i < 32; i++)
+                       p1[i] = NULL;
+       }
+
+       if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) {
+               p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL);
+               if (!p2) return -ENOMEM;
+               memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
+       }
+
+       p2[unicode & 0x3f] = fontpos;
+       
+       p->sum += (fontpos << 20) + unicode;
+
+       return 0;
+}
+
+/* ui is a leftover from using a hashtable, but might be used again */
+int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
+{
+       struct uni_pagedir *p, *q;
+  
+       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+       if (p && p->readonly) return -EIO;
+       if (!p || --p->refcount) {
+               q = kzalloc(sizeof(*p), GFP_KERNEL);
+               if (!q) {
+                       if (p) p->refcount++;
+                       return -ENOMEM;
+               }
+               q->refcount=1;
+               *vc->vc_uni_pagedir_loc = (unsigned long)q;
+       } else {
+               if (p == dflt) dflt = NULL;
+               p->refcount++;
+               p->sum = 0;
+               con_release_unimap(p);
+       }
+       return 0;
+}
+
+int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
+{
+       int err = 0, err1, i;
+       struct uni_pagedir *p, *q;
+
+       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+       if (p->readonly) return -EIO;
+       
+       if (!ct) return 0;
+       
+       if (p->refcount > 1) {
+               int j, k;
+               u16 **p1, *p2, l;
+               
+               err1 = con_clear_unimap(vc, NULL);
+               if (err1) return err1;
+               
+               q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+               for (i = 0, l = 0; i < 32; i++)
+               if ((p1 = p->uni_pgdir[i]))
+                       for (j = 0; j < 32; j++)
+                       if ((p2 = p1[j]))
+                               for (k = 0; k < 64; k++, l++)
+                               if (p2[k] != 0xffff) {
+                                       err1 = con_insert_unipair(q, l, p2[k]);
+                                       if (err1) {
+                                               p->refcount++;
+                                               *vc->vc_uni_pagedir_loc = (unsigned long)p;
+                                               con_release_unimap(q);
+                                               kfree(q);
+                                               return err1; 
+                                       }
+                               }
+               p = q;
+       } else if (p == dflt)
+               dflt = NULL;
+       
+       while (ct--) {
+               unsigned short unicode, fontpos;
+               __get_user(unicode, &list->unicode);
+               __get_user(fontpos, &list->fontpos);
+               if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0)
+                       err = err1;
+               list++;
+       }
+       
+       if (con_unify_unimap(vc, p))
+               return err;
+
+       for (i = 0; i <= 3; i++)
+               set_inverse_transl(vc, p, i); /* Update all inverse translations */
+       set_inverse_trans_unicode(vc, p);
+  
+       return err;
+}
+
+/* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
+   The representation used was the most compact I could come up
+   with.  This routine is executed at sys_setup time, and when the
+   PIO_FONTRESET ioctl is called. */
+
+int con_set_default_unimap(struct vc_data *vc)
+{
+       int i, j, err = 0, err1;
+       u16 *q;
+       struct uni_pagedir *p;
+
+       if (dflt) {
+               p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+               if (p == dflt)
+                       return 0;
+               dflt->refcount++;
+               *vc->vc_uni_pagedir_loc = (unsigned long)dflt;
+               if (p && --p->refcount) {
+                       con_release_unimap(p);
+                       kfree(p);
+               }
+               return 0;
+       }
+       
+       /* The default font is always 256 characters */
+
+       err = con_clear_unimap(vc, NULL);
+       if (err) return err;
+    
+       p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+       q = dfont_unitable;
+       
+       for (i = 0; i < 256; i++)
+               for (j = dfont_unicount[i]; j; j--) {
+                       err1 = con_insert_unipair(p, *(q++), i);
+                       if (err1)
+                               err = err1;
+               }
+                       
+       if (con_unify_unimap(vc, p)) {
+               dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+               return err;
+       }
+
+       for (i = 0; i <= 3; i++)
+               set_inverse_transl(vc, p, i);   /* Update all inverse translations */
+       set_inverse_trans_unicode(vc, p);
+       dflt = p;
+       return err;
+}
+EXPORT_SYMBOL(con_set_default_unimap);
+
+int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
+{
+       struct uni_pagedir *q;
+
+       if (!*src_vc->vc_uni_pagedir_loc)
+               return -EINVAL;
+       if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
+               return 0;
+       con_free_unimap(dst_vc);
+       q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc;
+       q->refcount++;
+       *dst_vc->vc_uni_pagedir_loc = (long)q;
+       return 0;
+}
+
+int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
+{
+       int i, j, k, ect;
+       u16 **p1, *p2;
+       struct uni_pagedir *p;
+
+       ect = 0;
+       if (*vc->vc_uni_pagedir_loc) {
+               p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+               for (i = 0; i < 32; i++)
+               if ((p1 = p->uni_pgdir[i]))
+                       for (j = 0; j < 32; j++)
+                       if ((p2 = *(p1++)))
+                               for (k = 0; k < 64; k++) {
+                                       if (*p2 < MAX_GLYPH && ect++ < ct) {
+                                               __put_user((u_short)((i<<11)+(j<<6)+k),
+                                                          &list->unicode);
+                                               __put_user((u_short) *p2, 
+                                                          &list->fontpos);
+                                               list++;
+                                       }
+                                       p2++;
+                               }
+       }
+       __put_user(ect, uct);
+       return ((ect <= ct) ? 0 : -ENOMEM);
+}
+
+void con_protect_unimap(struct vc_data *vc, int rdonly)
+{
+       struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+       
+       if (p)
+               p->readonly = rdonly;
+}
+
+/*
+ * Always use USER_MAP. These functions are used by the keyboard,
+ * which shouldn't be affected by G0/G1 switching, etc.
+ * If the user map still contains default values, i.e. the
+ * direct-to-font mapping, then assume user is using Latin1.
+ */
+/* may be called during an interrupt */
+u32 conv_8bit_to_uni(unsigned char c)
+{
+       unsigned short uni = translations[USER_MAP][c];
+       return uni == (0xf000 | c) ? c : uni;
+}
+
+int conv_uni_to_8bit(u32 uni)
+{
+       int c;
+       for (c = 0; c < 0x100; c++)
+               if (translations[USER_MAP][c] == uni ||
+                  (translations[USER_MAP][c] == (c | 0xf000) && uni == c))
+                       return c;
+       return -1;
+}
+
+int
+conv_uni_to_pc(struct vc_data *conp, long ucs) 
+{
+       int h;
+       u16 **p1, *p2;
+       struct uni_pagedir *p;
+  
+       /* Only 16-bit codes supported at this time */
+       if (ucs > 0xffff)
+               return -4;              /* Not found */
+       else if (ucs < 0x20)
+               return -1;              /* Not a printable character */
+       else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f))
+               return -2;                      /* Zero-width space */
+       /*
+        * UNI_DIRECT_BASE indicates the start of the region in the User Zone
+        * which always has a 1:1 mapping to the currently loaded font.  The
+        * UNI_DIRECT_MASK indicates the bit span of the region.
+        */
+       else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
+               return ucs & UNI_DIRECT_MASK;
+  
+       if (!*conp->vc_uni_pagedir_loc)
+               return -3;
+
+       p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc;  
+       if ((p1 = p->uni_pgdir[ucs >> 11]) &&
+           (p2 = p1[(ucs >> 6) & 0x1f]) &&
+           (h = p2[ucs & 0x3f]) < MAX_GLYPH)
+               return h;
+
+       return -4;              /* not found */
+}
+
+/*
+ * This is called at sys_setup time, after memory and the console are
+ * initialized.  It must be possible to call kmalloc(..., GFP_KERNEL)
+ * from this function, hence the call from sys_setup.
+ */
+void __init 
+console_map_init(void)
+{
+       int i;
+       
+       for (i = 0; i < MAX_NR_CONSOLES; i++)
+               if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
+                       con_set_default_unimap(vc_cons[i].d);
+}
+
+EXPORT_SYMBOL(con_copy_unimap);
diff --git a/drivers/tty/vt/cp437.uni b/drivers/tty/vt/cp437.uni
new file mode 100644 (file)
index 0000000..bc61634
--- /dev/null
@@ -0,0 +1,291 @@
+#
+# Unicode table for IBM Codepage 437.  Note that there are many more
+# substitutions that could be conceived (for example, thick-line
+# graphs probably should be replaced with double-line ones, accented
+# Latin characters should replaced with their nonaccented versions,
+# and some upper case Greek characters could be replaced by Latin), however,
+# I have limited myself to the Unicodes used by the kernel ISO 8859-1,
+# DEC VT, and IBM CP 437 tables.
+#
+# --------------------------------
+#
+# Basic IBM dingbats, some of which will never have a purpose clear
+# to mankind
+#
+0x00   U+0000
+0x01   U+263a
+0x02   U+263b
+0x03   U+2665
+0x04   U+2666 U+25c6
+0x05   U+2663
+0x06   U+2660
+0x07   U+2022
+0x08   U+25d8
+0x09   U+25cb
+0x0a   U+25d9
+0x0b   U+2642
+0x0c   U+2640
+0x0d   U+266a
+0x0e   U+266b
+0x0f   U+263c U+00a4
+0x10   U+25b6 U+25ba
+0x11   U+25c0 U+25c4
+0x12   U+2195
+0x13   U+203c
+0x14   U+00b6
+0x15   U+00a7
+0x16   U+25ac
+0x17   U+21a8
+0x18   U+2191
+0x19   U+2193
+0x1a   U+2192
+0x1b   U+2190
+0x1c   U+221f
+0x1d   U+2194
+0x1e   U+25b2
+0x1f   U+25bc
+#
+# The ASCII range is identity-mapped, but some of the characters also
+# have to act as substitutes, especially the upper-case characters.
+#
+0x20   U+0020
+0x21   U+0021
+0x22   U+0022 U+00a8
+0x23   U+0023
+0x24   U+0024
+0x25   U+0025
+0x26   U+0026
+0x27   U+0027 U+00b4
+0x28   U+0028
+0x29   U+0029
+0x2a   U+002a
+0x2b   U+002b
+0x2c   U+002c U+00b8
+0x2d   U+002d U+00ad
+0x2e   U+002e
+0x2f   U+002f
+0x30   U+0030
+0x31   U+0031
+0x32   U+0032
+0x33   U+0033
+0x34   U+0034
+0x35   U+0035
+0x36   U+0036
+0x37   U+0037
+0x38   U+0038
+0x39   U+0039
+0x3a   U+003a
+0x3b   U+003b
+0x3c   U+003c
+0x3d   U+003d
+0x3e   U+003e
+0x3f   U+003f
+0x40   U+0040
+0x41   U+0041 U+00c0 U+00c1 U+00c2 U+00c3
+0x42   U+0042
+0x43   U+0043 U+00a9
+0x44   U+0044 U+00d0
+0x45   U+0045 U+00c8 U+00ca U+00cb
+0x46   U+0046
+0x47   U+0047
+0x48   U+0048
+0x49   U+0049 U+00cc U+00cd U+00ce U+00cf
+0x4a   U+004a
+0x4b   U+004b U+212a
+0x4c   U+004c
+0x4d   U+004d
+0x4e   U+004e
+0x4f   U+004f U+00d2 U+00d3 U+00d4 U+00d5
+0x50   U+0050
+0x51   U+0051
+0x52   U+0052 U+00ae
+0x53   U+0053
+0x54   U+0054
+0x55   U+0055 U+00d9 U+00da U+00db
+0x56   U+0056
+0x57   U+0057
+0x58   U+0058
+0x59   U+0059 U+00dd
+0x5a   U+005a
+0x5b   U+005b
+0x5c   U+005c
+0x5d   U+005d
+0x5e   U+005e
+0x5f   U+005f U+23bd U+f804
+0x60   U+0060
+0x61   U+0061 U+00e3
+0x62   U+0062
+0x63   U+0063
+0x64   U+0064
+0x65   U+0065
+0x66   U+0066
+0x67   U+0067
+0x68   U+0068
+0x69   U+0069
+0x6a   U+006a
+0x6b   U+006b
+0x6c   U+006c
+0x6d   U+006d
+0x6e   U+006e
+0x6f   U+006f U+00f5
+0x70   U+0070
+0x71   U+0071
+0x72   U+0072
+0x73   U+0073
+0x74   U+0074
+0x75   U+0075
+0x76   U+0076
+0x77   U+0077
+0x78   U+0078 U+00d7
+0x79   U+0079 U+00fd
+0x7a   U+007a
+0x7b   U+007b
+0x7c   U+007c U+00a6
+0x7d   U+007d
+0x7e   U+007e
+#
+# Okay, what on Earth is this one supposed to be used for?
+#
+0x7f   U+2302
+#
+# Non-English characters, mostly lower case letters...
+#
+0x80   U+00c7
+0x81   U+00fc
+0x82   U+00e9
+0x83   U+00e2
+0x84   U+00e4
+0x85   U+00e0
+0x86   U+00e5
+0x87   U+00e7
+0x88   U+00ea
+0x89   U+00eb
+0x8a   U+00e8
+0x8b   U+00ef
+0x8c   U+00ee
+0x8d   U+00ec
+0x8e   U+00c4
+0x8f   U+00c5 U+212b
+0x90   U+00c9
+0x91   U+00e6
+0x92   U+00c6
+0x93   U+00f4
+0x94   U+00f6
+0x95   U+00f2
+0x96   U+00fb
+0x97   U+00f9
+0x98   U+00ff
+0x99   U+00d6
+0x9a   U+00dc
+0x9b   U+00a2
+0x9c   U+00a3
+0x9d   U+00a5
+0x9e   U+20a7
+0x9f   U+0192
+0xa0   U+00e1
+0xa1   U+00ed
+0xa2   U+00f3
+0xa3   U+00fa
+0xa4   U+00f1
+0xa5   U+00d1
+0xa6   U+00aa
+0xa7   U+00ba
+0xa8   U+00bf
+0xa9   U+2310
+0xaa   U+00ac
+0xab   U+00bd
+0xac   U+00bc
+0xad   U+00a1
+0xae   U+00ab
+0xaf   U+00bb
+#
+# Block graphics
+#
+0xb0   U+2591
+0xb1   U+2592
+0xb2   U+2593
+0xb3   U+2502
+0xb4   U+2524
+0xb5   U+2561
+0xb6   U+2562
+0xb7   U+2556
+0xb8   U+2555
+0xb9   U+2563
+0xba   U+2551
+0xbb   U+2557
+0xbc   U+255d
+0xbd   U+255c
+0xbe   U+255b
+0xbf   U+2510
+0xc0   U+2514
+0xc1   U+2534
+0xc2   U+252c
+0xc3   U+251c
+0xc4   U+2500
+0xc5   U+253c
+0xc6   U+255e
+0xc7   U+255f
+0xc8   U+255a
+0xc9   U+2554
+0xca   U+2569
+0xcb   U+2566
+0xcc   U+2560
+0xcd   U+2550
+0xce   U+256c
+0xcf   U+2567
+0xd0   U+2568
+0xd1   U+2564
+0xd2   U+2565
+0xd3   U+2559
+0xd4   U+2558
+0xd5   U+2552
+0xd6   U+2553
+0xd7   U+256b
+0xd8   U+256a
+0xd9   U+2518
+0xda   U+250c
+0xdb   U+2588
+0xdc   U+2584
+0xdd   U+258c
+0xde   U+2590
+0xdf   U+2580
+#
+# Greek letters and mathematical symbols
+#
+0xe0   U+03b1
+0xe1   U+03b2 U+00df
+0xe2   U+0393
+0xe3   U+03c0
+0xe4   U+03a3
+0xe5   U+03c3
+0xe6   U+00b5 U+03bc
+0xe7   U+03c4
+0xe8   U+03a6 U+00d8
+0xe9   U+0398
+0xea   U+03a9 U+2126
+0xeb   U+03b4 U+00f0
+0xec   U+221e
+0xed   U+03c6 U+00f8
+0xee   U+03b5 U+2208
+0xef   U+2229
+0xf0   U+2261
+0xf1   U+00b1
+0xf2   U+2265
+0xf3   U+2264
+0xf4   U+2320
+0xf5   U+2321
+0xf6   U+00f7
+0xf7   U+2248
+0xf8   U+00b0
+0xf9   U+2219
+0xfa   U+00b7
+0xfb   U+221a
+0xfc   U+207f
+0xfd   U+00b2
+#
+# Square bullet, non-spacing blank
+# Mapping U+fffd to the square bullet means it is the substitution
+# character
+# 
+0xfe   U+25a0 U+fffd
+0xff   U+00a0
diff --git a/drivers/tty/vt/defkeymap.c_shipped b/drivers/tty/vt/defkeymap.c_shipped
new file mode 100644 (file)
index 0000000..d2208df
--- /dev/null
@@ -0,0 +1,262 @@
+/* Do not edit this file! It was automatically generated by   */
+/*    loadkeys --mktable defkeymap.map > defkeymap.c          */
+
+#include <linux/types.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+
+u_short plain_map[NR_KEYS] = {
+       0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
+       0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf07f, 0xf009,
+       0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
+       0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73,
+       0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
+       0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76,
+       0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf30c,
+       0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+       0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf209, 0xf307,
+       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03c, 0xf10a,
+       0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short shift_map[NR_KEYS] = {
+       0xf200, 0xf01b, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e,
+       0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07f, 0xf009,
+       0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49,
+       0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf201, 0xf702, 0xfb41, 0xfb53,
+       0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a,
+       0xf022, 0xf07e, 0xf700, 0xf07c, 0xfb5a, 0xfb58, 0xfb43, 0xfb56,
+       0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf700, 0xf30c,
+       0xf703, 0xf020, 0xf207, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e,
+       0xf10f, 0xf110, 0xf111, 0xf112, 0xf113, 0xf213, 0xf203, 0xf307,
+       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03e, 0xf10a,
+       0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf20b, 0xf601, 0xf602, 0xf117, 0xf600, 0xf20a, 0xf115, 0xf116,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short altgr_map[NR_KEYS] = {
+       0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
+       0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200,
+       0xfb71, 0xfb77, 0xf918, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
+       0xfb6f, 0xfb70, 0xf200, 0xf07e, 0xf201, 0xf702, 0xf914, 0xfb73,
+       0xf917, 0xf919, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf200,
+       0xf200, 0xf200, 0xf700, 0xf200, 0xfb7a, 0xfb78, 0xf916, 0xfb76,
+       0xf915, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
+       0xf703, 0xf200, 0xf207, 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510,
+       0xf511, 0xf512, 0xf513, 0xf514, 0xf515, 0xf208, 0xf202, 0xf911,
+       0xf912, 0xf913, 0xf30b, 0xf90e, 0xf90f, 0xf910, 0xf30a, 0xf90b,
+       0xf90c, 0xf90d, 0xf90a, 0xf310, 0xf206, 0xf200, 0xf07c, 0xf516,
+       0xf517, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short ctrl_map[NR_KEYS] = {
+       0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e,
+       0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200,
+       0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
+       0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013,
+       0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
+       0xf007, 0xf000, 0xf700, 0xf01c, 0xf01a, 0xf018, 0xf003, 0xf016,
+       0xf002, 0xf00e, 0xf00d, 0xf200, 0xf20e, 0xf07f, 0xf700, 0xf30c,
+       0xf703, 0xf000, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+       0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf204, 0xf307,
+       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf10a,
+       0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short shift_ctrl_map[NR_KEYS] = {
+       0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200,
+       0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
+       0xf00f, 0xf010, 0xf200, 0xf200, 0xf201, 0xf702, 0xf001, 0xf013,
+       0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
+       0xf200, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016,
+       0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
+       0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf208, 0xf200, 0xf307,
+       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+       0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short alt_map[NR_KEYS] = {
+       0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836,
+       0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf87f, 0xf809,
+       0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869,
+       0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf80d, 0xf702, 0xf861, 0xf873,
+       0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b,
+       0xf827, 0xf860, 0xf700, 0xf85c, 0xf87a, 0xf878, 0xf863, 0xf876,
+       0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf700, 0xf30c,
+       0xf703, 0xf820, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504,
+       0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf209, 0xf907,
+       0xf908, 0xf909, 0xf30b, 0xf904, 0xf905, 0xf906, 0xf30a, 0xf901,
+       0xf902, 0xf903, 0xf900, 0xf310, 0xf206, 0xf200, 0xf83c, 0xf50a,
+       0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf118, 0xf210, 0xf211, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+u_short ctrl_alt_map[NR_KEYS] = {
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809,
+       0xf80f, 0xf810, 0xf200, 0xf200, 0xf201, 0xf702, 0xf801, 0xf813,
+       0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200,
+       0xf200, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816,
+       0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf30c,
+       0xf703, 0xf200, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504,
+       0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf200, 0xf307,
+       0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301,
+       0xf302, 0xf303, 0xf300, 0xf20c, 0xf206, 0xf200, 0xf200, 0xf50a,
+       0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+       0xf30e, 0xf702, 0xf30d, 0xf200, 0xf701, 0xf205, 0xf114, 0xf603,
+       0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf20c,
+       0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d,
+       0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+};
+
+ushort *key_maps[MAX_NR_KEYMAPS] = {
+       plain_map, shift_map, altgr_map, NULL,
+       ctrl_map, shift_ctrl_map, NULL, NULL,
+       alt_map, NULL, NULL, NULL,
+       ctrl_alt_map, NULL
+};
+
+unsigned int keymap_count = 7;
+
+/*
+ * Philosophy: most people do not define more strings, but they who do
+ * often want quite a lot of string space. So, we statically allocate
+ * the default and allocate dynamically in chunks of 512 bytes.
+ */
+
+char func_buf[] = {
+       '\033', '[', '[', 'A', 0, 
+       '\033', '[', '[', 'B', 0, 
+       '\033', '[', '[', 'C', 0, 
+       '\033', '[', '[', 'D', 0, 
+       '\033', '[', '[', 'E', 0, 
+       '\033', '[', '1', '7', '~', 0, 
+       '\033', '[', '1', '8', '~', 0, 
+       '\033', '[', '1', '9', '~', 0, 
+       '\033', '[', '2', '0', '~', 0, 
+       '\033', '[', '2', '1', '~', 0, 
+       '\033', '[', '2', '3', '~', 0, 
+       '\033', '[', '2', '4', '~', 0, 
+       '\033', '[', '2', '5', '~', 0, 
+       '\033', '[', '2', '6', '~', 0, 
+       '\033', '[', '2', '8', '~', 0, 
+       '\033', '[', '2', '9', '~', 0, 
+       '\033', '[', '3', '1', '~', 0, 
+       '\033', '[', '3', '2', '~', 0, 
+       '\033', '[', '3', '3', '~', 0, 
+       '\033', '[', '3', '4', '~', 0, 
+       '\033', '[', '1', '~', 0, 
+       '\033', '[', '2', '~', 0, 
+       '\033', '[', '3', '~', 0, 
+       '\033', '[', '4', '~', 0, 
+       '\033', '[', '5', '~', 0, 
+       '\033', '[', '6', '~', 0, 
+       '\033', '[', 'M', 0, 
+       '\033', '[', 'P', 0, 
+};
+
+char *funcbufptr = func_buf;
+int funcbufsize = sizeof(func_buf);
+int funcbufleft = 0;          /* space left */
+
+char *func_table[MAX_NR_FUNC] = {
+       func_buf + 0,
+       func_buf + 5,
+       func_buf + 10,
+       func_buf + 15,
+       func_buf + 20,
+       func_buf + 25,
+       func_buf + 31,
+       func_buf + 37,
+       func_buf + 43,
+       func_buf + 49,
+       func_buf + 55,
+       func_buf + 61,
+       func_buf + 67,
+       func_buf + 73,
+       func_buf + 79,
+       func_buf + 85,
+       func_buf + 91,
+       func_buf + 97,
+       func_buf + 103,
+       func_buf + 109,
+       func_buf + 115,
+       func_buf + 120,
+       func_buf + 125,
+       func_buf + 130,
+       func_buf + 135,
+       func_buf + 140,
+       func_buf + 145,
+       NULL,
+       NULL,
+       func_buf + 149,
+       NULL,
+};
+
+struct kbdiacruc accent_table[MAX_DIACR] = {
+       {'`', 'A', 0300},       {'`', 'a', 0340},
+       {'\'', 'A', 0301},      {'\'', 'a', 0341},
+       {'^', 'A', 0302},       {'^', 'a', 0342},
+       {'~', 'A', 0303},       {'~', 'a', 0343},
+       {'"', 'A', 0304},       {'"', 'a', 0344},
+       {'O', 'A', 0305},       {'o', 'a', 0345},
+       {'0', 'A', 0305},       {'0', 'a', 0345},
+       {'A', 'A', 0305},       {'a', 'a', 0345},
+       {'A', 'E', 0306},       {'a', 'e', 0346},
+       {',', 'C', 0307},       {',', 'c', 0347},
+       {'`', 'E', 0310},       {'`', 'e', 0350},
+       {'\'', 'E', 0311},      {'\'', 'e', 0351},
+       {'^', 'E', 0312},       {'^', 'e', 0352},
+       {'"', 'E', 0313},       {'"', 'e', 0353},
+       {'`', 'I', 0314},       {'`', 'i', 0354},
+       {'\'', 'I', 0315},      {'\'', 'i', 0355},
+       {'^', 'I', 0316},       {'^', 'i', 0356},
+       {'"', 'I', 0317},       {'"', 'i', 0357},
+       {'-', 'D', 0320},       {'-', 'd', 0360},
+       {'~', 'N', 0321},       {'~', 'n', 0361},
+       {'`', 'O', 0322},       {'`', 'o', 0362},
+       {'\'', 'O', 0323},      {'\'', 'o', 0363},
+       {'^', 'O', 0324},       {'^', 'o', 0364},
+       {'~', 'O', 0325},       {'~', 'o', 0365},
+       {'"', 'O', 0326},       {'"', 'o', 0366},
+       {'/', 'O', 0330},       {'/', 'o', 0370},
+       {'`', 'U', 0331},       {'`', 'u', 0371},
+       {'\'', 'U', 0332},      {'\'', 'u', 0372},
+       {'^', 'U', 0333},       {'^', 'u', 0373},
+       {'"', 'U', 0334},       {'"', 'u', 0374},
+       {'\'', 'Y', 0335},      {'\'', 'y', 0375},
+       {'T', 'H', 0336},       {'t', 'h', 0376},
+       {'s', 's', 0337},       {'"', 'y', 0377},
+       {'s', 'z', 0337},       {'i', 'j', 0377},
+};
+
+unsigned int accent_table_size = 68;
diff --git a/drivers/tty/vt/defkeymap.map b/drivers/tty/vt/defkeymap.map
new file mode 100644 (file)
index 0000000..50b30ca
--- /dev/null
@@ -0,0 +1,357 @@
+# Default kernel keymap. This uses 7 modifier combinations.
+keymaps 0-2,4-5,8,12
+# Change the above line into
+#      keymaps 0-2,4-6,8,12
+# in case you want the entries
+#      altgr   control keycode  83 = Boot            
+#      altgr   control keycode 111 = Boot            
+# below.
+#
+# In fact AltGr is used very little, and one more keymap can
+# be saved by mapping AltGr to Alt (and adapting a few entries):
+# keycode 100 = Alt
+#
+keycode   1 = Escape           Escape          
+       alt     keycode   1 = Meta_Escape     
+keycode   2 = one              exclam          
+       alt     keycode   2 = Meta_one        
+keycode   3 = two              at               at              
+       control keycode   3 = nul             
+       shift   control keycode   3 = nul             
+       alt     keycode   3 = Meta_two        
+keycode   4 = three            numbersign      
+       control keycode   4 = Escape          
+       alt     keycode   4 = Meta_three      
+keycode   5 = four             dollar           dollar          
+       control keycode   5 = Control_backslash
+       alt     keycode   5 = Meta_four       
+keycode   6 = five             percent         
+       control keycode   6 = Control_bracketright
+       alt     keycode   6 = Meta_five       
+keycode   7 = six              asciicircum     
+       control keycode   7 = Control_asciicircum
+       alt     keycode   7 = Meta_six        
+keycode   8 = seven            ampersand        braceleft       
+       control keycode   8 = Control_underscore
+       alt     keycode   8 = Meta_seven      
+keycode   9 = eight            asterisk         bracketleft     
+       control keycode   9 = Delete          
+       alt     keycode   9 = Meta_eight      
+keycode  10 = nine             parenleft        bracketright    
+       alt     keycode  10 = Meta_nine       
+keycode  11 = zero             parenright       braceright      
+       alt     keycode  11 = Meta_zero       
+keycode  12 = minus            underscore       backslash       
+       control keycode  12 = Control_underscore
+       shift   control keycode  12 = Control_underscore
+       alt     keycode  12 = Meta_minus      
+keycode  13 = equal            plus            
+       alt     keycode  13 = Meta_equal      
+keycode  14 = Delete           Delete          
+       control keycode  14 = BackSpace
+       alt     keycode  14 = Meta_Delete     
+keycode  15 = Tab              Tab             
+       alt     keycode  15 = Meta_Tab        
+keycode  16 = q               
+keycode  17 = w               
+keycode  18 = e
+       altgr   keycode  18 = Hex_E   
+keycode  19 = r               
+keycode  20 = t               
+keycode  21 = y               
+keycode  22 = u               
+keycode  23 = i               
+keycode  24 = o               
+keycode  25 = p               
+keycode  26 = bracketleft      braceleft       
+       control keycode  26 = Escape          
+       alt     keycode  26 = Meta_bracketleft
+keycode  27 = bracketright     braceright       asciitilde      
+       control keycode  27 = Control_bracketright
+       alt     keycode  27 = Meta_bracketright
+keycode  28 = Return          
+       alt     keycode  28 = Meta_Control_m  
+keycode  29 = Control         
+keycode  30 = a
+       altgr   keycode  30 = Hex_A
+keycode  31 = s               
+keycode  32 = d
+       altgr   keycode  32 = Hex_D   
+keycode  33 = f
+       altgr   keycode  33 = Hex_F               
+keycode  34 = g               
+keycode  35 = h               
+keycode  36 = j               
+keycode  37 = k               
+keycode  38 = l               
+keycode  39 = semicolon        colon           
+       alt     keycode  39 = Meta_semicolon  
+keycode  40 = apostrophe       quotedbl        
+       control keycode  40 = Control_g       
+       alt     keycode  40 = Meta_apostrophe 
+keycode  41 = grave            asciitilde      
+       control keycode  41 = nul             
+       alt     keycode  41 = Meta_grave      
+keycode  42 = Shift           
+keycode  43 = backslash        bar             
+       control keycode  43 = Control_backslash
+       alt     keycode  43 = Meta_backslash  
+keycode  44 = z               
+keycode  45 = x               
+keycode  46 = c
+       altgr   keycode  46 = Hex_C   
+keycode  47 = v               
+keycode  48 = b
+       altgr   keycode  48 = Hex_B
+keycode  49 = n               
+keycode  50 = m               
+keycode  51 = comma            less            
+       alt     keycode  51 = Meta_comma      
+keycode  52 = period           greater         
+       control keycode  52 = Compose         
+       alt     keycode  52 = Meta_period     
+keycode  53 = slash            question        
+       control keycode  53 = Delete          
+       alt     keycode  53 = Meta_slash      
+keycode  54 = Shift           
+keycode  55 = KP_Multiply     
+keycode  56 = Alt             
+keycode  57 = space            space           
+       control keycode  57 = nul             
+       alt     keycode  57 = Meta_space      
+keycode  58 = Caps_Lock       
+keycode  59 = F1               F11              Console_13      
+       control keycode  59 = F1              
+       alt     keycode  59 = Console_1       
+       control alt     keycode  59 = Console_1       
+keycode  60 = F2               F12              Console_14      
+       control keycode  60 = F2              
+       alt     keycode  60 = Console_2       
+       control alt     keycode  60 = Console_2       
+keycode  61 = F3               F13              Console_15      
+       control keycode  61 = F3              
+       alt     keycode  61 = Console_3       
+       control alt     keycode  61 = Console_3       
+keycode  62 = F4               F14              Console_16      
+       control keycode  62 = F4              
+       alt     keycode  62 = Console_4       
+       control alt     keycode  62 = Console_4       
+keycode  63 = F5               F15              Console_17      
+       control keycode  63 = F5              
+       alt     keycode  63 = Console_5       
+       control alt     keycode  63 = Console_5       
+keycode  64 = F6               F16              Console_18      
+       control keycode  64 = F6              
+       alt     keycode  64 = Console_6       
+       control alt     keycode  64 = Console_6       
+keycode  65 = F7               F17              Console_19      
+       control keycode  65 = F7              
+       alt     keycode  65 = Console_7       
+       control alt     keycode  65 = Console_7       
+keycode  66 = F8               F18              Console_20      
+       control keycode  66 = F8              
+       alt     keycode  66 = Console_8       
+       control alt     keycode  66 = Console_8       
+keycode  67 = F9               F19              Console_21      
+       control keycode  67 = F9              
+       alt     keycode  67 = Console_9       
+       control alt     keycode  67 = Console_9       
+keycode  68 = F10              F20              Console_22      
+       control keycode  68 = F10             
+       alt     keycode  68 = Console_10      
+       control alt     keycode  68 = Console_10      
+keycode  69 = Num_Lock
+       shift   keycode  69 = Bare_Num_Lock
+keycode  70 = Scroll_Lock      Show_Memory      Show_Registers  
+       control keycode  70 = Show_State      
+       alt     keycode  70 = Scroll_Lock     
+keycode  71 = KP_7            
+       alt     keycode  71 = Ascii_7         
+       altgr   keycode  71 = Hex_7         
+keycode  72 = KP_8            
+       alt     keycode  72 = Ascii_8         
+       altgr   keycode  72 = Hex_8         
+keycode  73 = KP_9            
+       alt     keycode  73 = Ascii_9         
+       altgr   keycode  73 = Hex_9         
+keycode  74 = KP_Subtract     
+keycode  75 = KP_4            
+       alt     keycode  75 = Ascii_4         
+       altgr   keycode  75 = Hex_4         
+keycode  76 = KP_5            
+       alt     keycode  76 = Ascii_5         
+       altgr   keycode  76 = Hex_5         
+keycode  77 = KP_6            
+       alt     keycode  77 = Ascii_6         
+       altgr   keycode  77 = Hex_6         
+keycode  78 = KP_Add          
+keycode  79 = KP_1            
+       alt     keycode  79 = Ascii_1         
+       altgr   keycode  79 = Hex_1         
+keycode  80 = KP_2            
+       alt     keycode  80 = Ascii_2         
+       altgr   keycode  80 = Hex_2         
+keycode  81 = KP_3            
+       alt     keycode  81 = Ascii_3         
+       altgr   keycode  81 = Hex_3         
+keycode  82 = KP_0            
+       alt     keycode  82 = Ascii_0         
+       altgr   keycode  82 = Hex_0         
+keycode  83 = KP_Period       
+#      altgr   control keycode  83 = Boot            
+       control alt     keycode  83 = Boot            
+keycode  84 = Last_Console    
+keycode  85 =
+keycode  86 = less             greater          bar             
+       alt     keycode  86 = Meta_less       
+keycode  87 = F11              F11              Console_23      
+       control keycode  87 = F11             
+       alt     keycode  87 = Console_11      
+       control alt     keycode  87 = Console_11      
+keycode  88 = F12              F12              Console_24      
+       control keycode  88 = F12             
+       alt     keycode  88 = Console_12      
+       control alt     keycode  88 = Console_12      
+keycode  89 =
+keycode  90 =
+keycode  91 =
+keycode  92 =
+keycode  93 =
+keycode  94 =
+keycode  95 =
+keycode  96 = KP_Enter        
+keycode  97 = Control         
+keycode  98 = KP_Divide       
+keycode  99 = Control_backslash
+       control keycode  99 = Control_backslash
+       alt     keycode  99 = Control_backslash
+keycode 100 = AltGr           
+keycode 101 = Break           
+keycode 102 = Find            
+keycode 103 = Up              
+keycode 104 = Prior           
+       shift   keycode 104 = Scroll_Backward 
+keycode 105 = Left            
+       alt     keycode 105 = Decr_Console
+keycode 106 = Right           
+       alt     keycode 106 = Incr_Console
+keycode 107 = Select          
+keycode 108 = Down            
+keycode 109 = Next            
+       shift   keycode 109 = Scroll_Forward  
+keycode 110 = Insert          
+keycode 111 = Remove          
+#      altgr   control keycode 111 = Boot            
+       control alt     keycode 111 = Boot            
+keycode 112 = Macro           
+keycode 113 = F13             
+keycode 114 = F14             
+keycode 115 = Help            
+keycode 116 = Do              
+keycode 117 = F17             
+keycode 118 = KP_MinPlus      
+keycode 119 = Pause           
+keycode 120 =
+keycode 121 =
+keycode 122 =
+keycode 123 =
+keycode 124 =
+keycode 125 =
+keycode 126 =
+keycode 127 =
+string F1 = "\033[[A"
+string F2 = "\033[[B"
+string F3 = "\033[[C"
+string F4 = "\033[[D"
+string F5 = "\033[[E"
+string F6 = "\033[17~"
+string F7 = "\033[18~"
+string F8 = "\033[19~"
+string F9 = "\033[20~"
+string F10 = "\033[21~"
+string F11 = "\033[23~"
+string F12 = "\033[24~"
+string F13 = "\033[25~"
+string F14 = "\033[26~"
+string F15 = "\033[28~"
+string F16 = "\033[29~"
+string F17 = "\033[31~"
+string F18 = "\033[32~"
+string F19 = "\033[33~"
+string F20 = "\033[34~"
+string Find = "\033[1~"
+string Insert = "\033[2~"
+string Remove = "\033[3~"
+string Select = "\033[4~"
+string Prior = "\033[5~"
+string Next = "\033[6~"
+string Macro = "\033[M"
+string Pause = "\033[P"
+compose '`' 'A' to 'À'
+compose '`' 'a' to 'à'
+compose '\'' 'A' to 'Á'
+compose '\'' 'a' to 'á'
+compose '^' 'A' to 'Â'
+compose '^' 'a' to 'â'
+compose '~' 'A' to 'Ã'
+compose '~' 'a' to 'ã'
+compose '"' 'A' to 'Ä'
+compose '"' 'a' to 'ä'
+compose 'O' 'A' to 'Å'
+compose 'o' 'a' to 'å'
+compose '0' 'A' to 'Å'
+compose '0' 'a' to 'å'
+compose 'A' 'A' to 'Å'
+compose 'a' 'a' to 'å'
+compose 'A' 'E' to 'Æ'
+compose 'a' 'e' to 'æ'
+compose ',' 'C' to 'Ç'
+compose ',' 'c' to 'ç'
+compose '`' 'E' to 'È'
+compose '`' 'e' to 'è'
+compose '\'' 'E' to 'É'
+compose '\'' 'e' to 'é'
+compose '^' 'E' to 'Ê'
+compose '^' 'e' to 'ê'
+compose '"' 'E' to 'Ë'
+compose '"' 'e' to 'ë'
+compose '`' 'I' to 'Ì'
+compose '`' 'i' to 'ì'
+compose '\'' 'I' to 'Í'
+compose '\'' 'i' to 'í'
+compose '^' 'I' to 'Î'
+compose '^' 'i' to 'î'
+compose '"' 'I' to 'Ï'
+compose '"' 'i' to 'ï'
+compose '-' 'D' to 'Ð'
+compose '-' 'd' to 'ð'
+compose '~' 'N' to 'Ñ'
+compose '~' 'n' to 'ñ'
+compose '`' 'O' to 'Ò'
+compose '`' 'o' to 'ò'
+compose '\'' 'O' to 'Ó'
+compose '\'' 'o' to 'ó'
+compose '^' 'O' to 'Ô'
+compose '^' 'o' to 'ô'
+compose '~' 'O' to 'Õ'
+compose '~' 'o' to 'õ'
+compose '"' 'O' to 'Ö'
+compose '"' 'o' to 'ö'
+compose '/' 'O' to 'Ø'
+compose '/' 'o' to 'ø'
+compose '`' 'U' to 'Ù'
+compose '`' 'u' to 'ù'
+compose '\'' 'U' to 'Ú'
+compose '\'' 'u' to 'ú'
+compose '^' 'U' to 'Û'
+compose '^' 'u' to 'û'
+compose '"' 'U' to 'Ü'
+compose '"' 'u' to 'ü'
+compose '\'' 'Y' to 'Ý'
+compose '\'' 'y' to 'ý'
+compose 'T' 'H' to 'Þ'
+compose 't' 'h' to 'þ'
+compose 's' 's' to 'ß'
+compose '"' 'y' to 'ÿ'
+compose 's' 'z' to 'ß'
+compose 'i' 'j' to 'ÿ'
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
new file mode 100644 (file)
index 0000000..e95d787
--- /dev/null
@@ -0,0 +1,1454 @@
+/*
+ * linux/drivers/char/keyboard.c
+ *
+ * Written for linux by Johan Myreen as a translation from
+ * the assembly version by Linus (with diacriticals added)
+ *
+ * Some additional features added by Christoph Niemann (ChN), March 1993
+ *
+ * Loadable keymaps by Risto Kankkunen, May 1993
+ *
+ * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
+ * Added decr/incr_console, dynamic keymaps, Unicode support,
+ * dynamic function/string keys, led setting,  Sept 1994
+ * `Sticky' modifier keys, 951006.
+ *
+ * 11-11-96: SAK should now work in the raw mode (Martin Mares)
+ *
+ * Modified to provide 'generic' keyboard support by Hamish Macdonald
+ * Merge with the m68k keyboard driver and split-off of the PC low-level
+ * parts by Geert Uytterhoeven, May 1997
+ *
+ * 27-05-97: Added support for the Magic SysRq Key (Martin Mares)
+ * 30-07-98: Dead keys redone, aeb@cwi.nl.
+ * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik)
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/consolemap.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/kbd_diacr.h>
+#include <linux/vt_kern.h>
+#include <linux/input.h>
+#include <linux/reboot.h>
+#include <linux/notifier.h>
+#include <linux/jiffies.h>
+
+extern void ctrl_alt_del(void);
+
+/*
+ * Exported functions/variables
+ */
+
+#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
+
+/*
+ * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
+ * This seems a good reason to start with NumLock off. On HIL keyboards
+ * of PARISC machines however there is no NumLock key and everyone expects the keypad
+ * to be used for numbers.
+ */
+
+#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
+#define KBD_DEFLEDS (1 << VC_NUMLOCK)
+#else
+#define KBD_DEFLEDS 0
+#endif
+
+#define KBD_DEFLOCK 0
+
+void compute_shiftstate(void);
+
+/*
+ * Handler Tables.
+ */
+
+#define K_HANDLERS\
+       k_self,         k_fn,           k_spec,         k_pad,\
+       k_dead,         k_cons,         k_cur,          k_shift,\
+       k_meta,         k_ascii,        k_lock,         k_lowercase,\
+       k_slock,        k_dead2,        k_brl,          k_ignore
+
+typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value,
+                           char up_flag);
+static k_handler_fn K_HANDLERS;
+static k_handler_fn *k_handler[16] = { K_HANDLERS };
+
+#define FN_HANDLERS\
+       fn_null,        fn_enter,       fn_show_ptregs, fn_show_mem,\
+       fn_show_state,  fn_send_intr,   fn_lastcons,    fn_caps_toggle,\
+       fn_num,         fn_hold,        fn_scroll_forw, fn_scroll_back,\
+       fn_boot_it,     fn_caps_on,     fn_compose,     fn_SAK,\
+       fn_dec_console, fn_inc_console, fn_spawn_con,   fn_bare_num
+
+typedef void (fn_handler_fn)(struct vc_data *vc);
+static fn_handler_fn FN_HANDLERS;
+static fn_handler_fn *fn_handler[] = { FN_HANDLERS };
+
+/*
+ * Variables exported for vt_ioctl.c
+ */
+
+/* maximum values each key_handler can handle */
+const int max_vals[] = {
+       255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1,
+       NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1,
+       255, NR_LOCK - 1, 255, NR_BRL - 1
+};
+
+const int NR_TYPES = ARRAY_SIZE(max_vals);
+
+struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+EXPORT_SYMBOL_GPL(kbd_table);
+static struct kbd_struct *kbd = kbd_table;
+
+struct vt_spawn_console vt_spawn_con = {
+       .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock),
+       .pid  = NULL,
+       .sig  = 0,
+};
+
+/*
+ * Variables exported for vt.c
+ */
+
+int shift_state = 0;
+
+/*
+ * Internal Data.
+ */
+
+static struct input_handler kbd_handler;
+static DEFINE_SPINLOCK(kbd_event_lock);
+static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */
+static unsigned char shift_down[NR_SHIFT];             /* shift state counters.. */
+static bool dead_key_next;
+static int npadch = -1;                                        /* -1 or number assembled on pad */
+static unsigned int diacr;
+static char rep;                                       /* flag telling character repeat */
+
+static unsigned char ledstate = 0xff;                  /* undefined */
+static unsigned char ledioctl;
+
+static struct ledptr {
+       unsigned int *addr;
+       unsigned int mask;
+       unsigned char valid:1;
+} ledptrs[3];
+
+/*
+ * Notifier list for console keyboard events
+ */
+static ATOMIC_NOTIFIER_HEAD(keyboard_notifier_list);
+
+int register_keyboard_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_register(&keyboard_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(register_keyboard_notifier);
+
+int unregister_keyboard_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_unregister(&keyboard_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_keyboard_notifier);
+
+/*
+ * Translation of scancodes to keycodes. We set them on only the first
+ * keyboard in the list that accepts the scancode and keycode.
+ * Explanation for not choosing the first attached keyboard anymore:
+ *  USB keyboards for example have two event devices: one for all "normal"
+ *  keys and one for extra function keys (like "volume up", "make coffee",
+ *  etc.). So this means that scancodes for the extra function keys won't
+ *  be valid for the first event device, but will be for the second.
+ */
+
+struct getset_keycode_data {
+       struct input_keymap_entry ke;
+       int error;
+};
+
+static int getkeycode_helper(struct input_handle *handle, void *data)
+{
+       struct getset_keycode_data *d = data;
+
+       d->error = input_get_keycode(handle->dev, &d->ke);
+
+       return d->error == 0; /* stop as soon as we successfully get one */
+}
+
+int getkeycode(unsigned int scancode)
+{
+       struct getset_keycode_data d = {
+               .ke     = {
+                       .flags          = 0,
+                       .len            = sizeof(scancode),
+                       .keycode        = 0,
+               },
+               .error  = -ENODEV,
+       };
+
+       memcpy(d.ke.scancode, &scancode, sizeof(scancode));
+
+       input_handler_for_each_handle(&kbd_handler, &d, getkeycode_helper);
+
+       return d.error ?: d.ke.keycode;
+}
+
+static int setkeycode_helper(struct input_handle *handle, void *data)
+{
+       struct getset_keycode_data *d = data;
+
+       d->error = input_set_keycode(handle->dev, &d->ke);
+
+       return d->error == 0; /* stop as soon as we successfully set one */
+}
+
+int setkeycode(unsigned int scancode, unsigned int keycode)
+{
+       struct getset_keycode_data d = {
+               .ke     = {
+                       .flags          = 0,
+                       .len            = sizeof(scancode),
+                       .keycode        = keycode,
+               },
+               .error  = -ENODEV,
+       };
+
+       memcpy(d.ke.scancode, &scancode, sizeof(scancode));
+
+       input_handler_for_each_handle(&kbd_handler, &d, setkeycode_helper);
+
+       return d.error;
+}
+
+/*
+ * Making beeps and bells. Note that we prefer beeps to bells, but when
+ * shutting the sound off we do both.
+ */
+
+static int kd_sound_helper(struct input_handle *handle, void *data)
+{
+       unsigned int *hz = data;
+       struct input_dev *dev = handle->dev;
+
+       if (test_bit(EV_SND, dev->evbit)) {
+               if (test_bit(SND_TONE, dev->sndbit)) {
+                       input_inject_event(handle, EV_SND, SND_TONE, *hz);
+                       if (*hz)
+                               return 0;
+               }
+               if (test_bit(SND_BELL, dev->sndbit))
+                       input_inject_event(handle, EV_SND, SND_BELL, *hz ? 1 : 0);
+       }
+
+       return 0;
+}
+
+static void kd_nosound(unsigned long ignored)
+{
+       static unsigned int zero;
+
+       input_handler_for_each_handle(&kbd_handler, &zero, kd_sound_helper);
+}
+
+static DEFINE_TIMER(kd_mksound_timer, kd_nosound, 0, 0);
+
+void kd_mksound(unsigned int hz, unsigned int ticks)
+{
+       del_timer_sync(&kd_mksound_timer);
+
+       input_handler_for_each_handle(&kbd_handler, &hz, kd_sound_helper);
+
+       if (hz && ticks)
+               mod_timer(&kd_mksound_timer, jiffies + ticks);
+}
+EXPORT_SYMBOL(kd_mksound);
+
+/*
+ * Setting the keyboard rate.
+ */
+
+static int kbd_rate_helper(struct input_handle *handle, void *data)
+{
+       struct input_dev *dev = handle->dev;
+       struct kbd_repeat *rep = data;
+
+       if (test_bit(EV_REP, dev->evbit)) {
+
+               if (rep[0].delay > 0)
+                       input_inject_event(handle,
+                                          EV_REP, REP_DELAY, rep[0].delay);
+               if (rep[0].period > 0)
+                       input_inject_event(handle,
+                                          EV_REP, REP_PERIOD, rep[0].period);
+
+               rep[1].delay = dev->rep[REP_DELAY];
+               rep[1].period = dev->rep[REP_PERIOD];
+       }
+
+       return 0;
+}
+
+int kbd_rate(struct kbd_repeat *rep)
+{
+       struct kbd_repeat data[2] = { *rep };
+
+       input_handler_for_each_handle(&kbd_handler, data, kbd_rate_helper);
+       *rep = data[1]; /* Copy currently used settings */
+
+       return 0;
+}
+
+/*
+ * Helper Functions.
+ */
+static void put_queue(struct vc_data *vc, int ch)
+{
+       struct tty_struct *tty = vc->port.tty;
+
+       if (tty) {
+               tty_insert_flip_char(tty, ch, 0);
+               con_schedule_flip(tty);
+       }
+}
+
+static void puts_queue(struct vc_data *vc, char *cp)
+{
+       struct tty_struct *tty = vc->port.tty;
+
+       if (!tty)
+               return;
+
+       while (*cp) {
+               tty_insert_flip_char(tty, *cp, 0);
+               cp++;
+       }
+       con_schedule_flip(tty);
+}
+
+static void applkey(struct vc_data *vc, int key, char mode)
+{
+       static char buf[] = { 0x1b, 'O', 0x00, 0x00 };
+
+       buf[1] = (mode ? 'O' : '[');
+       buf[2] = key;
+       puts_queue(vc, buf);
+}
+
+/*
+ * Many other routines do put_queue, but I think either
+ * they produce ASCII, or they produce some user-assigned
+ * string, and in both cases we might assume that it is
+ * in utf-8 already.
+ */
+static void to_utf8(struct vc_data *vc, uint c)
+{
+       if (c < 0x80)
+               /*  0******* */
+               put_queue(vc, c);
+       else if (c < 0x800) {
+               /* 110***** 10****** */
+               put_queue(vc, 0xc0 | (c >> 6));
+               put_queue(vc, 0x80 | (c & 0x3f));
+       } else if (c < 0x10000) {
+               if (c >= 0xD800 && c < 0xE000)
+                       return;
+               if (c == 0xFFFF)
+                       return;
+               /* 1110**** 10****** 10****** */
+               put_queue(vc, 0xe0 | (c >> 12));
+               put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
+               put_queue(vc, 0x80 | (c & 0x3f));
+       } else if (c < 0x110000) {
+               /* 11110*** 10****** 10****** 10****** */
+               put_queue(vc, 0xf0 | (c >> 18));
+               put_queue(vc, 0x80 | ((c >> 12) & 0x3f));
+               put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
+               put_queue(vc, 0x80 | (c & 0x3f));
+       }
+}
+
+/*
+ * Called after returning from RAW mode or when changing consoles - recompute
+ * shift_down[] and shift_state from key_down[] maybe called when keymap is
+ * undefined, so that shiftkey release is seen
+ */
+void compute_shiftstate(void)
+{
+       unsigned int i, j, k, sym, val;
+
+       shift_state = 0;
+       memset(shift_down, 0, sizeof(shift_down));
+
+       for (i = 0; i < ARRAY_SIZE(key_down); i++) {
+
+               if (!key_down[i])
+                       continue;
+
+               k = i * BITS_PER_LONG;
+
+               for (j = 0; j < BITS_PER_LONG; j++, k++) {
+
+                       if (!test_bit(k, key_down))
+                               continue;
+
+                       sym = U(key_maps[0][k]);
+                       if (KTYP(sym) != KT_SHIFT && KTYP(sym) != KT_SLOCK)
+                               continue;
+
+                       val = KVAL(sym);
+                       if (val == KVAL(K_CAPSSHIFT))
+                               val = KVAL(K_SHIFT);
+
+                       shift_down[val]++;
+                       shift_state |= (1 << val);
+               }
+       }
+}
+
+/*
+ * We have a combining character DIACR here, followed by the character CH.
+ * If the combination occurs in the table, return the corresponding value.
+ * Otherwise, if CH is a space or equals DIACR, return DIACR.
+ * Otherwise, conclude that DIACR was not combining after all,
+ * queue it and return CH.
+ */
+static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch)
+{
+       unsigned int d = diacr;
+       unsigned int i;
+
+       diacr = 0;
+
+       if ((d & ~0xff) == BRL_UC_ROW) {
+               if ((ch & ~0xff) == BRL_UC_ROW)
+                       return d | ch;
+       } else {
+               for (i = 0; i < accent_table_size; i++)
+                       if (accent_table[i].diacr == d && accent_table[i].base == ch)
+                               return accent_table[i].result;
+       }
+
+       if (ch == ' ' || ch == (BRL_UC_ROW|0) || ch == d)
+               return d;
+
+       if (kbd->kbdmode == VC_UNICODE)
+               to_utf8(vc, d);
+       else {
+               int c = conv_uni_to_8bit(d);
+               if (c != -1)
+                       put_queue(vc, c);
+       }
+
+       return ch;
+}
+
+/*
+ * Special function handlers
+ */
+static void fn_enter(struct vc_data *vc)
+{
+       if (diacr) {
+               if (kbd->kbdmode == VC_UNICODE)
+                       to_utf8(vc, diacr);
+               else {
+                       int c = conv_uni_to_8bit(diacr);
+                       if (c != -1)
+                               put_queue(vc, c);
+               }
+               diacr = 0;
+       }
+
+       put_queue(vc, 13);
+       if (vc_kbd_mode(kbd, VC_CRLF))
+               put_queue(vc, 10);
+}
+
+static void fn_caps_toggle(struct vc_data *vc)
+{
+       if (rep)
+               return;
+
+       chg_vc_kbd_led(kbd, VC_CAPSLOCK);
+}
+
+static void fn_caps_on(struct vc_data *vc)
+{
+       if (rep)
+               return;
+
+       set_vc_kbd_led(kbd, VC_CAPSLOCK);
+}
+
+static void fn_show_ptregs(struct vc_data *vc)
+{
+       struct pt_regs *regs = get_irq_regs();
+
+       if (regs)
+               show_regs(regs);
+}
+
+static void fn_hold(struct vc_data *vc)
+{
+       struct tty_struct *tty = vc->port.tty;
+
+       if (rep || !tty)
+               return;
+
+       /*
+        * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty);
+        * these routines are also activated by ^S/^Q.
+        * (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
+        */
+       if (tty->stopped)
+               start_tty(tty);
+       else
+               stop_tty(tty);
+}
+
+static void fn_num(struct vc_data *vc)
+{
+       if (vc_kbd_mode(kbd, VC_APPLIC))
+               applkey(vc, 'P', 1);
+       else
+               fn_bare_num(vc);
+}
+
+/*
+ * Bind this to Shift-NumLock if you work in application keypad mode
+ * but want to be able to change the NumLock flag.
+ * Bind this to NumLock if you prefer that the NumLock key always
+ * changes the NumLock flag.
+ */
+static void fn_bare_num(struct vc_data *vc)
+{
+       if (!rep)
+               chg_vc_kbd_led(kbd, VC_NUMLOCK);
+}
+
+static void fn_lastcons(struct vc_data *vc)
+{
+       /* switch to the last used console, ChN */
+       set_console(last_console);
+}
+
+static void fn_dec_console(struct vc_data *vc)
+{
+       int i, cur = fg_console;
+
+       /* Currently switching?  Queue this next switch relative to that. */
+       if (want_console != -1)
+               cur = want_console;
+
+       for (i = cur - 1; i != cur; i--) {
+               if (i == -1)
+                       i = MAX_NR_CONSOLES - 1;
+               if (vc_cons_allocated(i))
+                       break;
+       }
+       set_console(i);
+}
+
+static void fn_inc_console(struct vc_data *vc)
+{
+       int i, cur = fg_console;
+
+       /* Currently switching?  Queue this next switch relative to that. */
+       if (want_console != -1)
+               cur = want_console;
+
+       for (i = cur+1; i != cur; i++) {
+               if (i == MAX_NR_CONSOLES)
+                       i = 0;
+               if (vc_cons_allocated(i))
+                       break;
+       }
+       set_console(i);
+}
+
+static void fn_send_intr(struct vc_data *vc)
+{
+       struct tty_struct *tty = vc->port.tty;
+
+       if (!tty)
+               return;
+       tty_insert_flip_char(tty, 0, TTY_BREAK);
+       con_schedule_flip(tty);
+}
+
+static void fn_scroll_forw(struct vc_data *vc)
+{
+       scrollfront(vc, 0);
+}
+
+static void fn_scroll_back(struct vc_data *vc)
+{
+       scrollback(vc, 0);
+}
+
+static void fn_show_mem(struct vc_data *vc)
+{
+       show_mem();
+}
+
+static void fn_show_state(struct vc_data *vc)
+{
+       show_state();
+}
+
+static void fn_boot_it(struct vc_data *vc)
+{
+       ctrl_alt_del();
+}
+
+static void fn_compose(struct vc_data *vc)
+{
+       dead_key_next = true;
+}
+
+static void fn_spawn_con(struct vc_data *vc)
+{
+       spin_lock(&vt_spawn_con.lock);
+       if (vt_spawn_con.pid)
+               if (kill_pid(vt_spawn_con.pid, vt_spawn_con.sig, 1)) {
+                       put_pid(vt_spawn_con.pid);
+                       vt_spawn_con.pid = NULL;
+               }
+       spin_unlock(&vt_spawn_con.lock);
+}
+
+static void fn_SAK(struct vc_data *vc)
+{
+       struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
+       schedule_work(SAK_work);
+}
+
+static void fn_null(struct vc_data *vc)
+{
+       compute_shiftstate();
+}
+
+/*
+ * Special key handlers
+ */
+static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag)
+{
+}
+
+static void k_spec(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       if (up_flag)
+               return;
+       if (value >= ARRAY_SIZE(fn_handler))
+               return;
+       if ((kbd->kbdmode == VC_RAW ||
+            kbd->kbdmode == VC_MEDIUMRAW) &&
+            value != KVAL(K_SAK))
+               return;         /* SAK is allowed even in raw mode */
+       fn_handler[value](vc);
+}
+
+static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       pr_err("k_lowercase was called - impossible\n");
+}
+
+static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag)
+{
+       if (up_flag)
+               return;         /* no action, if this is a key release */
+
+       if (diacr)
+               value = handle_diacr(vc, value);
+
+       if (dead_key_next) {
+               dead_key_next = false;
+               diacr = value;
+               return;
+       }
+       if (kbd->kbdmode == VC_UNICODE)
+               to_utf8(vc, value);
+       else {
+               int c = conv_uni_to_8bit(value);
+               if (c != -1)
+                       put_queue(vc, c);
+       }
+}
+
+/*
+ * Handle dead key. Note that we now may have several
+ * dead keys modifying the same character. Very useful
+ * for Vietnamese.
+ */
+static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag)
+{
+       if (up_flag)
+               return;
+
+       diacr = (diacr ? handle_diacr(vc, value) : value);
+}
+
+static void k_self(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       k_unicode(vc, conv_8bit_to_uni(value), up_flag);
+}
+
+static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       k_deadunicode(vc, value, up_flag);
+}
+
+/*
+ * Obsolete - for backwards compatibility only
+ */
+static void k_dead(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
+
+       k_deadunicode(vc, ret_diacr[value], up_flag);
+}
+
+static void k_cons(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       if (up_flag)
+               return;
+
+       set_console(value);
+}
+
+static void k_fn(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       if (up_flag)
+               return;
+
+       if ((unsigned)value < ARRAY_SIZE(func_table)) {
+               if (func_table[value])
+                       puts_queue(vc, func_table[value]);
+       } else
+               pr_err("k_fn called with value=%d\n", value);
+}
+
+static void k_cur(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       static const char cur_chars[] = "BDCA";
+
+       if (up_flag)
+               return;
+
+       applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE));
+}
+
+static void k_pad(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       static const char pad_chars[] = "0123456789+-*/\015,.?()#";
+       static const char app_map[] = "pqrstuvwxylSRQMnnmPQS";
+
+       if (up_flag)
+               return;         /* no action, if this is a key release */
+
+       /* kludge... shift forces cursor/number keys */
+       if (vc_kbd_mode(kbd, VC_APPLIC) && !shift_down[KG_SHIFT]) {
+               applkey(vc, app_map[value], 1);
+               return;
+       }
+
+       if (!vc_kbd_led(kbd, VC_NUMLOCK)) {
+
+               switch (value) {
+               case KVAL(K_PCOMMA):
+               case KVAL(K_PDOT):
+                       k_fn(vc, KVAL(K_REMOVE), 0);
+                       return;
+               case KVAL(K_P0):
+                       k_fn(vc, KVAL(K_INSERT), 0);
+                       return;
+               case KVAL(K_P1):
+                       k_fn(vc, KVAL(K_SELECT), 0);
+                       return;
+               case KVAL(K_P2):
+                       k_cur(vc, KVAL(K_DOWN), 0);
+                       return;
+               case KVAL(K_P3):
+                       k_fn(vc, KVAL(K_PGDN), 0);
+                       return;
+               case KVAL(K_P4):
+                       k_cur(vc, KVAL(K_LEFT), 0);
+                       return;
+               case KVAL(K_P6):
+                       k_cur(vc, KVAL(K_RIGHT), 0);
+                       return;
+               case KVAL(K_P7):
+                       k_fn(vc, KVAL(K_FIND), 0);
+                       return;
+               case KVAL(K_P8):
+                       k_cur(vc, KVAL(K_UP), 0);
+                       return;
+               case KVAL(K_P9):
+                       k_fn(vc, KVAL(K_PGUP), 0);
+                       return;
+               case KVAL(K_P5):
+                       applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC));
+                       return;
+               }
+       }
+
+       put_queue(vc, pad_chars[value]);
+       if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
+               put_queue(vc, 10);
+}
+
+static void k_shift(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       int old_state = shift_state;
+
+       if (rep)
+               return;
+       /*
+        * Mimic typewriter:
+        * a CapsShift key acts like Shift but undoes CapsLock
+        */
+       if (value == KVAL(K_CAPSSHIFT)) {
+               value = KVAL(K_SHIFT);
+               if (!up_flag)
+                       clr_vc_kbd_led(kbd, VC_CAPSLOCK);
+       }
+
+       if (up_flag) {
+               /*
+                * handle the case that two shift or control
+                * keys are depressed simultaneously
+                */
+               if (shift_down[value])
+                       shift_down[value]--;
+       } else
+               shift_down[value]++;
+
+       if (shift_down[value])
+               shift_state |= (1 << value);
+       else
+               shift_state &= ~(1 << value);
+
+       /* kludge */
+       if (up_flag && shift_state != old_state && npadch != -1) {
+               if (kbd->kbdmode == VC_UNICODE)
+                       to_utf8(vc, npadch);
+               else
+                       put_queue(vc, npadch & 0xff);
+               npadch = -1;
+       }
+}
+
+static void k_meta(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       if (up_flag)
+               return;
+
+       if (vc_kbd_mode(kbd, VC_META)) {
+               put_queue(vc, '\033');
+               put_queue(vc, value);
+       } else
+               put_queue(vc, value | 0x80);
+}
+
+static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       int base;
+
+       if (up_flag)
+               return;
+
+       if (value < 10) {
+               /* decimal input of code, while Alt depressed */
+               base = 10;
+       } else {
+               /* hexadecimal input of code, while AltGr depressed */
+               value -= 10;
+               base = 16;
+       }
+
+       if (npadch == -1)
+               npadch = value;
+       else
+               npadch = npadch * base + value;
+}
+
+static void k_lock(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       if (up_flag || rep)
+               return;
+
+       chg_vc_kbd_lock(kbd, value);
+}
+
+static void k_slock(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       k_shift(vc, value, up_flag);
+       if (up_flag || rep)
+               return;
+
+       chg_vc_kbd_slock(kbd, value);
+       /* try to make Alt, oops, AltGr and such work */
+       if (!key_maps[kbd->lockstate ^ kbd->slockstate]) {
+               kbd->slockstate = 0;
+               chg_vc_kbd_slock(kbd, value);
+       }
+}
+
+/* by default, 300ms interval for combination release */
+static unsigned brl_timeout = 300;
+MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for commit on first key release)");
+module_param(brl_timeout, uint, 0644);
+
+static unsigned brl_nbchords = 1;
+MODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)");
+module_param(brl_nbchords, uint, 0644);
+
+static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag)
+{
+       static unsigned long chords;
+       static unsigned committed;
+
+       if (!brl_nbchords)
+               k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag);
+       else {
+               committed |= pattern;
+               chords++;
+               if (chords == brl_nbchords) {
+                       k_unicode(vc, BRL_UC_ROW | committed, up_flag);
+                       chords = 0;
+                       committed = 0;
+               }
+       }
+}
+
+static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
+{
+       static unsigned pressed, committing;
+       static unsigned long releasestart;
+
+       if (kbd->kbdmode != VC_UNICODE) {
+               if (!up_flag)
+                       pr_warning("keyboard mode must be unicode for braille patterns\n");
+               return;
+       }
+
+       if (!value) {
+               k_unicode(vc, BRL_UC_ROW, up_flag);
+               return;
+       }
+
+       if (value > 8)
+               return;
+
+       if (!up_flag) {
+               pressed |= 1 << (value - 1);
+               if (!brl_timeout)
+                       committing = pressed;
+       } else if (brl_timeout) {
+               if (!committing ||
+                   time_after(jiffies,
+                              releasestart + msecs_to_jiffies(brl_timeout))) {
+                       committing = pressed;
+                       releasestart = jiffies;
+               }
+               pressed &= ~(1 << (value - 1));
+               if (!pressed && committing) {
+                       k_brlcommit(vc, committing, 0);
+                       committing = 0;
+               }
+       } else {
+               if (committing) {
+                       k_brlcommit(vc, committing, 0);
+                       committing = 0;
+               }
+               pressed &= ~(1 << (value - 1));
+       }
+}
+
+/*
+ * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
+ * or (ii) whatever pattern of lights people want to show using KDSETLED,
+ * or (iii) specified bits of specified words in kernel memory.
+ */
+unsigned char getledstate(void)
+{
+       return ledstate;
+}
+
+void setledstate(struct kbd_struct *kbd, unsigned int led)
+{
+       if (!(led & ~7)) {
+               ledioctl = led;
+               kbd->ledmode = LED_SHOW_IOCTL;
+       } else
+               kbd->ledmode = LED_SHOW_FLAGS;
+
+       set_leds();
+}
+
+static inline unsigned char getleds(void)
+{
+       struct kbd_struct *kbd = kbd_table + fg_console;
+       unsigned char leds;
+       int i;
+
+       if (kbd->ledmode == LED_SHOW_IOCTL)
+               return ledioctl;
+
+       leds = kbd->ledflagstate;
+
+       if (kbd->ledmode == LED_SHOW_MEM) {
+               for (i = 0; i < 3; i++)
+                       if (ledptrs[i].valid) {
+                               if (*ledptrs[i].addr & ledptrs[i].mask)
+                                       leds |= (1 << i);
+                               else
+                                       leds &= ~(1 << i);
+                       }
+       }
+       return leds;
+}
+
+static int kbd_update_leds_helper(struct input_handle *handle, void *data)
+{
+       unsigned char leds = *(unsigned char *)data;
+
+       if (test_bit(EV_LED, handle->dev->evbit)) {
+               input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
+               input_inject_event(handle, EV_LED, LED_NUML,    !!(leds & 0x02));
+               input_inject_event(handle, EV_LED, LED_CAPSL,   !!(leds & 0x04));
+               input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
+       }
+
+       return 0;
+}
+
+/*
+ * This is the tasklet that updates LED state on all keyboards
+ * attached to the box. The reason we use tasklet is that we
+ * need to handle the scenario when keyboard handler is not
+ * registered yet but we already getting updates form VT to
+ * update led state.
+ */
+static void kbd_bh(unsigned long dummy)
+{
+       unsigned char leds = getleds();
+
+       if (leds != ledstate) {
+               input_handler_for_each_handle(&kbd_handler, &leds,
+                                             kbd_update_leds_helper);
+               ledstate = leds;
+       }
+}
+
+DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
+
+#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
+    defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
+    defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
+    (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) ||\
+    defined(CONFIG_AVR32)
+
+#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
+                       ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
+
+static const unsigned short x86_keycodes[256] =
+       { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+        32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+        48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+        64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+        80, 81, 82, 83, 84,118, 86, 87, 88,115,120,119,121,112,123, 92,
+       284,285,309,  0,312, 91,327,328,329,331,333,335,336,337,338,339,
+       367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349,
+       360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355,
+       103,104,105,275,287,279,258,106,274,107,294,364,358,363,362,361,
+       291,108,381,281,290,272,292,305,280, 99,112,257,306,359,113,114,
+       264,117,271,374,379,265,266, 93, 94, 95, 85,259,375,260, 90,116,
+       377,109,111,277,278,282,283,295,296,297,299,300,301,293,303,307,
+       308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330,
+       332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 };
+
+#ifdef CONFIG_SPARC
+static int sparc_l1_a_state;
+extern void sun_do_break(void);
+#endif
+
+static int emulate_raw(struct vc_data *vc, unsigned int keycode,
+                      unsigned char up_flag)
+{
+       int code;
+
+       switch (keycode) {
+
+       case KEY_PAUSE:
+               put_queue(vc, 0xe1);
+               put_queue(vc, 0x1d | up_flag);
+               put_queue(vc, 0x45 | up_flag);
+               break;
+
+       case KEY_HANGEUL:
+               if (!up_flag)
+                       put_queue(vc, 0xf2);
+               break;
+
+       case KEY_HANJA:
+               if (!up_flag)
+                       put_queue(vc, 0xf1);
+               break;
+
+       case KEY_SYSRQ:
+               /*
+                * Real AT keyboards (that's what we're trying
+                * to emulate here emit 0xe0 0x2a 0xe0 0x37 when
+                * pressing PrtSc/SysRq alone, but simply 0x54
+                * when pressing Alt+PrtSc/SysRq.
+                */
+               if (test_bit(KEY_LEFTALT, key_down) ||
+                   test_bit(KEY_RIGHTALT, key_down)) {
+                       put_queue(vc, 0x54 | up_flag);
+               } else {
+                       put_queue(vc, 0xe0);
+                       put_queue(vc, 0x2a | up_flag);
+                       put_queue(vc, 0xe0);
+                       put_queue(vc, 0x37 | up_flag);
+               }
+               break;
+
+       default:
+               if (keycode > 255)
+                       return -1;
+
+               code = x86_keycodes[keycode];
+               if (!code)
+                       return -1;
+
+               if (code & 0x100)
+                       put_queue(vc, 0xe0);
+               put_queue(vc, (code & 0x7f) | up_flag);
+
+               break;
+       }
+
+       return 0;
+}
+
+#else
+
+#define HW_RAW(dev)    0
+
+static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag)
+{
+       if (keycode > 127)
+               return -1;
+
+       put_queue(vc, keycode | up_flag);
+       return 0;
+}
+#endif
+
+static void kbd_rawcode(unsigned char data)
+{
+       struct vc_data *vc = vc_cons[fg_console].d;
+
+       kbd = kbd_table + vc->vc_num;
+       if (kbd->kbdmode == VC_RAW)
+               put_queue(vc, data);
+}
+
+static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
+{
+       struct vc_data *vc = vc_cons[fg_console].d;
+       unsigned short keysym, *key_map;
+       unsigned char type;
+       bool raw_mode;
+       struct tty_struct *tty;
+       int shift_final;
+       struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down };
+       int rc;
+
+       tty = vc->port.tty;
+
+       if (tty && (!tty->driver_data)) {
+               /* No driver data? Strange. Okay we fix it then. */
+               tty->driver_data = vc;
+       }
+
+       kbd = kbd_table + vc->vc_num;
+
+#ifdef CONFIG_SPARC
+       if (keycode == KEY_STOP)
+               sparc_l1_a_state = down;
+#endif
+
+       rep = (down == 2);
+
+       raw_mode = (kbd->kbdmode == VC_RAW);
+       if (raw_mode && !hw_raw)
+               if (emulate_raw(vc, keycode, !down << 7))
+                       if (keycode < BTN_MISC && printk_ratelimit())
+                               pr_warning("can't emulate rawmode for keycode %d\n",
+                                          keycode);
+
+#ifdef CONFIG_SPARC
+       if (keycode == KEY_A && sparc_l1_a_state) {
+               sparc_l1_a_state = false;
+               sun_do_break();
+       }
+#endif
+
+       if (kbd->kbdmode == VC_MEDIUMRAW) {
+               /*
+                * This is extended medium raw mode, with keys above 127
+                * encoded as 0, high 7 bits, low 7 bits, with the 0 bearing
+                * the 'up' flag if needed. 0 is reserved, so this shouldn't
+                * interfere with anything else. The two bytes after 0 will
+                * always have the up flag set not to interfere with older
+                * applications. This allows for 16384 different keycodes,
+                * which should be enough.
+                */
+               if (keycode < 128) {
+                       put_queue(vc, keycode | (!down << 7));
+               } else {
+                       put_queue(vc, !down << 7);
+                       put_queue(vc, (keycode >> 7) | 0x80);
+                       put_queue(vc, keycode | 0x80);
+               }
+               raw_mode = true;
+       }
+
+       if (down)
+               set_bit(keycode, key_down);
+       else
+               clear_bit(keycode, key_down);
+
+       if (rep &&
+           (!vc_kbd_mode(kbd, VC_REPEAT) ||
+            (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) {
+               /*
+                * Don't repeat a key if the input buffers are not empty and the
+                * characters get aren't echoed locally. This makes key repeat
+                * usable with slow applications and under heavy loads.
+                */
+               return;
+       }
+
+       param.shift = shift_final = (shift_state | kbd->slockstate) ^ kbd->lockstate;
+       param.ledstate = kbd->ledflagstate;
+       key_map = key_maps[shift_final];
+
+       rc = atomic_notifier_call_chain(&keyboard_notifier_list,
+                                       KBD_KEYCODE, &param);
+       if (rc == NOTIFY_STOP || !key_map) {
+               atomic_notifier_call_chain(&keyboard_notifier_list,
+                                          KBD_UNBOUND_KEYCODE, &param);
+               compute_shiftstate();
+               kbd->slockstate = 0;
+               return;
+       }
+
+       if (keycode < NR_KEYS)
+               keysym = key_map[keycode];
+       else if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8)
+               keysym = U(K(KT_BRL, keycode - KEY_BRL_DOT1 + 1));
+       else
+               return;
+
+       type = KTYP(keysym);
+
+       if (type < 0xf0) {
+               param.value = keysym;
+               rc = atomic_notifier_call_chain(&keyboard_notifier_list,
+                                               KBD_UNICODE, &param);
+               if (rc != NOTIFY_STOP)
+                       if (down && !raw_mode)
+                               to_utf8(vc, keysym);
+               return;
+       }
+
+       type -= 0xf0;
+
+       if (type == KT_LETTER) {
+               type = KT_LATIN;
+               if (vc_kbd_led(kbd, VC_CAPSLOCK)) {
+                       key_map = key_maps[shift_final ^ (1 << KG_SHIFT)];
+                       if (key_map)
+                               keysym = key_map[keycode];
+               }
+       }
+
+       param.value = keysym;
+       rc = atomic_notifier_call_chain(&keyboard_notifier_list,
+                                       KBD_KEYSYM, &param);
+       if (rc == NOTIFY_STOP)
+               return;
+
+       if (raw_mode && type != KT_SPEC && type != KT_SHIFT)
+               return;
+
+       (*k_handler[type])(vc, keysym & 0xff, !down);
+
+       param.ledstate = kbd->ledflagstate;
+       atomic_notifier_call_chain(&keyboard_notifier_list, KBD_POST_KEYSYM, &param);
+
+       if (type != KT_SLOCK)
+               kbd->slockstate = 0;
+}
+
+static void kbd_event(struct input_handle *handle, unsigned int event_type,
+                     unsigned int event_code, int value)
+{
+       /* We are called with interrupts disabled, just take the lock */
+       spin_lock(&kbd_event_lock);
+
+       if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
+               kbd_rawcode(value);
+       if (event_type == EV_KEY)
+               kbd_keycode(event_code, value, HW_RAW(handle->dev));
+
+       spin_unlock(&kbd_event_lock);
+
+       tasklet_schedule(&keyboard_tasklet);
+       do_poke_blanked_console = 1;
+       schedule_console_callback();
+}
+
+static bool kbd_match(struct input_handler *handler, struct input_dev *dev)
+{
+       int i;
+
+       if (test_bit(EV_SND, dev->evbit))
+               return true;
+
+       if (test_bit(EV_KEY, dev->evbit)) {
+               for (i = KEY_RESERVED; i < BTN_MISC; i++)
+                       if (test_bit(i, dev->keybit))
+                               return true;
+               for (i = KEY_BRL_DOT1; i <= KEY_BRL_DOT10; i++)
+                       if (test_bit(i, dev->keybit))
+                               return true;
+       }
+
+       return false;
+}
+
+/*
+ * When a keyboard (or other input device) is found, the kbd_connect
+ * function is called. The function then looks at the device, and if it
+ * likes it, it can open it and get events from it. In this (kbd_connect)
+ * function, we should decide which VT to bind that keyboard to initially.
+ */
+static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
+                       const struct input_device_id *id)
+{
+       struct input_handle *handle;
+       int error;
+
+       handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+       if (!handle)
+               return -ENOMEM;
+
+       handle->dev = dev;
+       handle->handler = handler;
+       handle->name = "kbd";
+
+       error = input_register_handle(handle);
+       if (error)
+               goto err_free_handle;
+
+       error = input_open_device(handle);
+       if (error)
+               goto err_unregister_handle;
+
+       return 0;
+
+ err_unregister_handle:
+       input_unregister_handle(handle);
+ err_free_handle:
+       kfree(handle);
+       return error;
+}
+
+static void kbd_disconnect(struct input_handle *handle)
+{
+       input_close_device(handle);
+       input_unregister_handle(handle);
+       kfree(handle);
+}
+
+/*
+ * Start keyboard handler on the new keyboard by refreshing LED state to
+ * match the rest of the system.
+ */
+static void kbd_start(struct input_handle *handle)
+{
+       tasklet_disable(&keyboard_tasklet);
+
+       if (ledstate != 0xff)
+               kbd_update_leds_helper(handle, &ledstate);
+
+       tasklet_enable(&keyboard_tasklet);
+}
+
+static const struct input_device_id kbd_ids[] = {
+       {
+                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+                .evbit = { BIT_MASK(EV_KEY) },
+        },
+
+       {
+                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+                .evbit = { BIT_MASK(EV_SND) },
+        },
+
+       { },    /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(input, kbd_ids);
+
+static struct input_handler kbd_handler = {
+       .event          = kbd_event,
+       .match          = kbd_match,
+       .connect        = kbd_connect,
+       .disconnect     = kbd_disconnect,
+       .start          = kbd_start,
+       .name           = "kbd",
+       .id_table       = kbd_ids,
+};
+
+int __init kbd_init(void)
+{
+       int i;
+       int error;
+
+        for (i = 0; i < MAX_NR_CONSOLES; i++) {
+               kbd_table[i].ledflagstate = KBD_DEFLEDS;
+               kbd_table[i].default_ledflagstate = KBD_DEFLEDS;
+               kbd_table[i].ledmode = LED_SHOW_FLAGS;
+               kbd_table[i].lockstate = KBD_DEFLOCK;
+               kbd_table[i].slockstate = 0;
+               kbd_table[i].modeflags = KBD_DEFMODE;
+               kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
+       }
+
+       error = input_register_handler(&kbd_handler);
+       if (error)
+               return error;
+
+       tasklet_enable(&keyboard_tasklet);
+       tasklet_schedule(&keyboard_tasklet);
+
+       return 0;
+}
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
new file mode 100644 (file)
index 0000000..ebae344
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * linux/drivers/char/selection.c
+ *
+ * This module exports the functions:
+ *
+ *     'int set_selection(struct tiocl_selection __user *, struct tty_struct *)'
+ *     'void clear_selection(void)'
+ *     'int paste_selection(struct tty_struct *)'
+ *     'int sel_loadlut(char __user *)'
+ *
+ * Now that /dev/vcs exists, most of this can disappear again.
+ */
+
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <asm/uaccess.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
+#include <linux/tiocl.h>
+#include <linux/console.h>
+#include <linux/smp_lock.h>
+
+/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
+#define isspace(c)     ((c) == ' ')
+
+extern void poke_blanked_console(void);
+
+/* Variables for selection control. */
+/* Use a dynamic buffer, instead of static (Dec 1994) */
+struct vc_data *sel_cons;              /* must not be deallocated */
+static int use_unicode;
+static volatile int sel_start = -1;    /* cleared by clear_selection */
+static int sel_end;
+static int sel_buffer_lth;
+static char *sel_buffer;
+
+/* clear_selection, highlight and highlight_pointer can be called
+   from interrupt (via scrollback/front) */
+
+/* set reverse video on characters s-e of console with selection. */
+static inline void highlight(const int s, const int e)
+{
+       invert_screen(sel_cons, s, e-s+2, 1);
+}
+
+/* use complementary color to show the pointer */
+static inline void highlight_pointer(const int where)
+{
+       complement_pos(sel_cons, where);
+}
+
+static u16
+sel_pos(int n)
+{
+       return inverse_translate(sel_cons, screen_glyph(sel_cons, n),
+                               use_unicode);
+}
+
+/* remove the current selection highlight, if any,
+   from the console holding the selection. */
+void
+clear_selection(void) {
+       highlight_pointer(-1); /* hide the pointer */
+       if (sel_start != -1) {
+               highlight(sel_start, sel_end);
+               sel_start = -1;
+       }
+}
+
+/*
+ * User settable table: what characters are to be considered alphabetic?
+ * 256 bits
+ */
+static u32 inwordLut[8]={
+  0x00000000, /* control chars     */
+  0x03FF0000, /* digits            */
+  0x87FFFFFE, /* uppercase and '_' */
+  0x07FFFFFE, /* lowercase         */
+  0x00000000,
+  0x00000000,
+  0xFF7FFFFF, /* latin-1 accented letters, not multiplication sign */
+  0xFF7FFFFF  /* latin-1 accented letters, not division sign */
+};
+
+static inline int inword(const u16 c) {
+       return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1);
+}
+
+/* set inwordLut contents. Invoked by ioctl(). */
+int sel_loadlut(char __user *p)
+{
+       return copy_from_user(inwordLut, (u32 __user *)(p+4), 32) ? -EFAULT : 0;
+}
+
+/* does screen address p correspond to character at LH/RH edge of screen? */
+static inline int atedge(const int p, int size_row)
+{
+       return (!(p % size_row) || !((p + 2) % size_row));
+}
+
+/* constrain v such that v <= u */
+static inline unsigned short limit(const unsigned short v, const unsigned short u)
+{
+       return (v > u) ? u : v;
+}
+
+/* stores the char in UTF8 and returns the number of bytes used (1-3) */
+static int store_utf8(u16 c, char *p)
+{
+       if (c < 0x80) {
+               /*  0******* */
+               p[0] = c;
+               return 1;
+       } else if (c < 0x800) {
+               /* 110***** 10****** */
+               p[0] = 0xc0 | (c >> 6);
+               p[1] = 0x80 | (c & 0x3f);
+               return 2;
+       } else {
+               /* 1110**** 10****** 10****** */
+               p[0] = 0xe0 | (c >> 12);
+               p[1] = 0x80 | ((c >> 6) & 0x3f);
+               p[2] = 0x80 | (c & 0x3f);
+               return 3;
+       }
+}
+
+/* set the current selection. Invoked by ioctl() or by kernel code. */
+int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty)
+{
+       struct vc_data *vc = vc_cons[fg_console].d;
+       int sel_mode, new_sel_start, new_sel_end, spc;
+       char *bp, *obp;
+       int i, ps, pe, multiplier;
+       u16 c;
+       struct kbd_struct *kbd = kbd_table + fg_console;
+
+       poke_blanked_console();
+
+       { unsigned short xs, ys, xe, ye;
+
+         if (!access_ok(VERIFY_READ, sel, sizeof(*sel)))
+               return -EFAULT;
+         __get_user(xs, &sel->xs);
+         __get_user(ys, &sel->ys);
+         __get_user(xe, &sel->xe);
+         __get_user(ye, &sel->ye);
+         __get_user(sel_mode, &sel->sel_mode);
+         xs--; ys--; xe--; ye--;
+         xs = limit(xs, vc->vc_cols - 1);
+         ys = limit(ys, vc->vc_rows - 1);
+         xe = limit(xe, vc->vc_cols - 1);
+         ye = limit(ye, vc->vc_rows - 1);
+         ps = ys * vc->vc_size_row + (xs << 1);
+         pe = ye * vc->vc_size_row + (xe << 1);
+
+         if (sel_mode == TIOCL_SELCLEAR) {
+             /* useful for screendump without selection highlights */
+             clear_selection();
+             return 0;
+         }
+
+         if (mouse_reporting() && (sel_mode & TIOCL_SELMOUSEREPORT)) {
+             mouse_report(tty, sel_mode & TIOCL_SELBUTTONMASK, xs, ys);
+             return 0;
+         }
+        }
+
+       if (ps > pe)    /* make sel_start <= sel_end */
+       {
+               int tmp = ps;
+               ps = pe;
+               pe = tmp;
+       }
+
+       if (sel_cons != vc_cons[fg_console].d) {
+               clear_selection();
+               sel_cons = vc_cons[fg_console].d;
+       }
+       use_unicode = kbd && kbd->kbdmode == VC_UNICODE;
+
+       switch (sel_mode)
+       {
+               case TIOCL_SELCHAR:     /* character-by-character selection */
+                       new_sel_start = ps;
+                       new_sel_end = pe;
+                       break;
+               case TIOCL_SELWORD:     /* word-by-word selection */
+                       spc = isspace(sel_pos(ps));
+                       for (new_sel_start = ps; ; ps -= 2)
+                       {
+                               if ((spc && !isspace(sel_pos(ps))) ||
+                                   (!spc && !inword(sel_pos(ps))))
+                                       break;
+                               new_sel_start = ps;
+                               if (!(ps % vc->vc_size_row))
+                                       break;
+                       }
+                       spc = isspace(sel_pos(pe));
+                       for (new_sel_end = pe; ; pe += 2)
+                       {
+                               if ((spc && !isspace(sel_pos(pe))) ||
+                                   (!spc && !inword(sel_pos(pe))))
+                                       break;
+                               new_sel_end = pe;
+                               if (!((pe + 2) % vc->vc_size_row))
+                                       break;
+                       }
+                       break;
+               case TIOCL_SELLINE:     /* line-by-line selection */
+                       new_sel_start = ps - ps % vc->vc_size_row;
+                       new_sel_end = pe + vc->vc_size_row
+                                   - pe % vc->vc_size_row - 2;
+                       break;
+               case TIOCL_SELPOINTER:
+                       highlight_pointer(pe);
+                       return 0;
+               default:
+                       return -EINVAL;
+       }
+
+       /* remove the pointer */
+       highlight_pointer(-1);
+
+       /* select to end of line if on trailing space */
+       if (new_sel_end > new_sel_start &&
+               !atedge(new_sel_end, vc->vc_size_row) &&
+               isspace(sel_pos(new_sel_end))) {
+               for (pe = new_sel_end + 2; ; pe += 2)
+                       if (!isspace(sel_pos(pe)) ||
+                           atedge(pe, vc->vc_size_row))
+                               break;
+               if (isspace(sel_pos(pe)))
+                       new_sel_end = pe;
+       }
+       if (sel_start == -1)    /* no current selection */
+               highlight(new_sel_start, new_sel_end);
+       else if (new_sel_start == sel_start)
+       {
+               if (new_sel_end == sel_end)     /* no action required */
+                       return 0;
+               else if (new_sel_end > sel_end) /* extend to right */
+                       highlight(sel_end + 2, new_sel_end);
+               else                            /* contract from right */
+                       highlight(new_sel_end + 2, sel_end);
+       }
+       else if (new_sel_end == sel_end)
+       {
+               if (new_sel_start < sel_start)  /* extend to left */
+                       highlight(new_sel_start, sel_start - 2);
+               else                            /* contract from left */
+                       highlight(sel_start, new_sel_start - 2);
+       }
+       else    /* some other case; start selection from scratch */
+       {
+               clear_selection();
+               highlight(new_sel_start, new_sel_end);
+       }
+       sel_start = new_sel_start;
+       sel_end = new_sel_end;
+
+       /* Allocate a new buffer before freeing the old one ... */
+       multiplier = use_unicode ? 3 : 1;  /* chars can take up to 3 bytes */
+       bp = kmalloc(((sel_end-sel_start)/2+1)*multiplier, GFP_KERNEL);
+       if (!bp) {
+               printk(KERN_WARNING "selection: kmalloc() failed\n");
+               clear_selection();
+               return -ENOMEM;
+       }
+       kfree(sel_buffer);
+       sel_buffer = bp;
+
+       obp = bp;
+       for (i = sel_start; i <= sel_end; i += 2) {
+               c = sel_pos(i);
+               if (use_unicode)
+                       bp += store_utf8(c, bp);
+               else
+                       *bp++ = c;
+               if (!isspace(c))
+                       obp = bp;
+               if (! ((i + 2) % vc->vc_size_row)) {
+                       /* strip trailing blanks from line and add newline,
+                          unless non-space at end of line. */
+                       if (obp != bp) {
+                               bp = obp;
+                               *bp++ = '\r';
+                       }
+                       obp = bp;
+               }
+       }
+       sel_buffer_lth = bp - sel_buffer;
+       return 0;
+}
+
+/* Insert the contents of the selection buffer into the
+ * queue of the tty associated with the current console.
+ * Invoked by ioctl().
+ */
+int paste_selection(struct tty_struct *tty)
+{
+       struct vc_data *vc = tty->driver_data;
+       int     pasted = 0;
+       unsigned int count;
+       struct  tty_ldisc *ld;
+       DECLARE_WAITQUEUE(wait, current);
+
+       /* always called with BTM from vt_ioctl */
+       WARN_ON(!tty_locked());
+
+       acquire_console_sem();
+       poke_blanked_console();
+       release_console_sem();
+
+       ld = tty_ldisc_ref(tty);
+       if (!ld) {
+               tty_unlock();
+               ld = tty_ldisc_ref_wait(tty);
+               tty_lock();
+       }
+
+       add_wait_queue(&vc->paste_wait, &wait);
+       while (sel_buffer && sel_buffer_lth > pasted) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (test_bit(TTY_THROTTLED, &tty->flags)) {
+                       schedule();
+                       continue;
+               }
+               count = sel_buffer_lth - pasted;
+               count = min(count, tty->receive_room);
+               tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
+                                                               NULL, count);
+               pasted += count;
+       }
+       remove_wait_queue(&vc->paste_wait, &wait);
+       __set_current_state(TASK_RUNNING);
+
+       tty_ldisc_deref(ld);
+       return 0;
+}
diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c
new file mode 100644 (file)
index 0000000..273ab44
--- /dev/null
@@ -0,0 +1,644 @@
+/*
+ * linux/drivers/char/vc_screen.c
+ *
+ * Provide access to virtual console memory.
+ * /dev/vcs0: the screen as it is being viewed right now (possibly scrolled)
+ * /dev/vcsN: the screen of /dev/ttyN (1 <= N <= 63)
+ *            [minor: N]
+ *
+ * /dev/vcsaN: idem, but including attributes, and prefixed with
+ *     the 4 bytes lines,columns,x,y (as screendump used to give).
+ *     Attribute/character pair is in native endianity.
+ *            [minor: N+128]
+ *
+ * This replaces screendump and part of selection, so that the system
+ * administrator can control access using file system permissions.
+ *
+ * aeb@cwi.nl - efter Friedas begravelse - 950211
+ *
+ * machek@k332.feld.cvut.cz - modified not to send characters to wrong console
+ *      - fixed some fatal off-by-one bugs (0-- no longer == -1 -> looping and looping and looping...)
+ *      - making it shorter - scr_readw are macros which expand in PRETTY long code
+ */
+
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/kbd_kern.h>
+#include <linux/console.h>
+#include <linux/device.h>
+#include <linux/smp_lock.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/notifier.h>
+
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+
+#undef attr
+#undef org
+#undef addr
+#define HEADER_SIZE    4
+
+struct vcs_poll_data {
+       struct notifier_block notifier;
+       unsigned int cons_num;
+       bool seen_last_update;
+       wait_queue_head_t waitq;
+       struct fasync_struct *fasync;
+};
+
+static int
+vcs_notifier(struct notifier_block *nb, unsigned long code, void *_param)
+{
+       struct vt_notifier_param *param = _param;
+       struct vc_data *vc = param->vc;
+       struct vcs_poll_data *poll =
+               container_of(nb, struct vcs_poll_data, notifier);
+       int currcons = poll->cons_num;
+
+       if (code != VT_UPDATE)
+               return NOTIFY_DONE;
+
+       if (currcons == 0)
+               currcons = fg_console;
+       else
+               currcons--;
+       if (currcons != vc->vc_num)
+               return NOTIFY_DONE;
+
+       poll->seen_last_update = false;
+       wake_up_interruptible(&poll->waitq);
+       kill_fasync(&poll->fasync, SIGIO, POLL_IN);
+       return NOTIFY_OK;
+}
+
+static void
+vcs_poll_data_free(struct vcs_poll_data *poll)
+{
+       unregister_vt_notifier(&poll->notifier);
+       kfree(poll);
+}
+
+static struct vcs_poll_data *
+vcs_poll_data_get(struct file *file)
+{
+       struct vcs_poll_data *poll = file->private_data;
+
+       if (poll)
+               return poll;
+
+       poll = kzalloc(sizeof(*poll), GFP_KERNEL);
+       if (!poll)
+               return NULL;
+       poll->cons_num = iminor(file->f_path.dentry->d_inode) & 127;
+       init_waitqueue_head(&poll->waitq);
+       poll->notifier.notifier_call = vcs_notifier;
+       if (register_vt_notifier(&poll->notifier) != 0) {
+               kfree(poll);
+               return NULL;
+       }
+
+       /*
+        * This code may be called either through ->poll() or ->fasync().
+        * If we have two threads using the same file descriptor, they could
+        * both enter this function, both notice that the structure hasn't
+        * been allocated yet and go ahead allocating it in parallel, but
+        * only one of them must survive and be shared otherwise we'd leak
+        * memory with a dangling notifier callback.
+        */
+       spin_lock(&file->f_lock);
+       if (!file->private_data) {
+               file->private_data = poll;
+       } else {
+               /* someone else raced ahead of us */
+               vcs_poll_data_free(poll);
+               poll = file->private_data;
+       }
+       spin_unlock(&file->f_lock);
+
+       return poll;
+}
+
+static int
+vcs_size(struct inode *inode)
+{
+       int size;
+       int minor = iminor(inode);
+       int currcons = minor & 127;
+       struct vc_data *vc;
+
+       if (currcons == 0)
+               currcons = fg_console;
+       else
+               currcons--;
+       if (!vc_cons_allocated(currcons))
+               return -ENXIO;
+       vc = vc_cons[currcons].d;
+
+       size = vc->vc_rows * vc->vc_cols;
+
+       if (minor & 128)
+               size = 2*size + HEADER_SIZE;
+       return size;
+}
+
+static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
+{
+       int size;
+
+       mutex_lock(&con_buf_mtx);
+       size = vcs_size(file->f_path.dentry->d_inode);
+       switch (orig) {
+               default:
+                       mutex_unlock(&con_buf_mtx);
+                       return -EINVAL;
+               case 2:
+                       offset += size;
+                       break;
+               case 1:
+                       offset += file->f_pos;
+               case 0:
+                       break;
+       }
+       if (offset < 0 || offset > size) {
+               mutex_unlock(&con_buf_mtx);
+               return -EINVAL;
+       }
+       file->f_pos = offset;
+       mutex_unlock(&con_buf_mtx);
+       return file->f_pos;
+}
+
+
+static ssize_t
+vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       unsigned int currcons = iminor(inode);
+       struct vc_data *vc;
+       struct vcs_poll_data *poll;
+       long pos;
+       long viewed, attr, read;
+       int col, maxcol;
+       unsigned short *org = NULL;
+       ssize_t ret;
+
+       mutex_lock(&con_buf_mtx);
+
+       pos = *ppos;
+
+       /* Select the proper current console and verify
+        * sanity of the situation under the console lock.
+        */
+       acquire_console_sem();
+
+       attr = (currcons & 128);
+       currcons = (currcons & 127);
+       if (currcons == 0) {
+               currcons = fg_console;
+               viewed = 1;
+       } else {
+               currcons--;
+               viewed = 0;
+       }
+       ret = -ENXIO;
+       if (!vc_cons_allocated(currcons))
+               goto unlock_out;
+       vc = vc_cons[currcons].d;
+
+       ret = -EINVAL;
+       if (pos < 0)
+               goto unlock_out;
+       poll = file->private_data;
+       if (count && poll)
+               poll->seen_last_update = true;
+       read = 0;
+       ret = 0;
+       while (count) {
+               char *con_buf0, *con_buf_start;
+               long this_round, size;
+               ssize_t orig_count;
+               long p = pos;
+
+               /* Check whether we are above size each round,
+                * as copy_to_user at the end of this loop
+                * could sleep.
+                */
+               size = vcs_size(inode);
+               if (pos >= size)
+                       break;
+               if (count > size - pos)
+                       count = size - pos;
+
+               this_round = count;
+               if (this_round > CON_BUF_SIZE)
+                       this_round = CON_BUF_SIZE;
+
+               /* Perform the whole read into the local con_buf.
+                * Then we can drop the console spinlock and safely
+                * attempt to move it to userspace.
+                */
+
+               con_buf_start = con_buf0 = con_buf;
+               orig_count = this_round;
+               maxcol = vc->vc_cols;
+               if (!attr) {
+                       org = screen_pos(vc, p, viewed);
+                       col = p % maxcol;
+                       p += maxcol - col;
+                       while (this_round-- > 0) {
+                               *con_buf0++ = (vcs_scr_readw(vc, org++) & 0xff);
+                               if (++col == maxcol) {
+                                       org = screen_pos(vc, p, viewed);
+                                       col = 0;
+                                       p += maxcol;
+                               }
+                       }
+               } else {
+                       if (p < HEADER_SIZE) {
+                               size_t tmp_count;
+
+                               con_buf0[0] = (char)vc->vc_rows;
+                               con_buf0[1] = (char)vc->vc_cols;
+                               getconsxy(vc, con_buf0 + 2);
+
+                               con_buf_start += p;
+                               this_round += p;
+                               if (this_round > CON_BUF_SIZE) {
+                                       this_round = CON_BUF_SIZE;
+                                       orig_count = this_round - p;
+                               }
+
+                               tmp_count = HEADER_SIZE;
+                               if (tmp_count > this_round)
+                                       tmp_count = this_round;
+
+                               /* Advance state pointers and move on. */
+                               this_round -= tmp_count;
+                               p = HEADER_SIZE;
+                               con_buf0 = con_buf + HEADER_SIZE;
+                               /* If this_round >= 0, then p is even... */
+                       } else if (p & 1) {
+                               /* Skip first byte for output if start address is odd
+                                * Update region sizes up/down depending on free
+                                * space in buffer.
+                                */
+                               con_buf_start++;
+                               if (this_round < CON_BUF_SIZE)
+                                       this_round++;
+                               else
+                                       orig_count--;
+                       }
+                       if (this_round > 0) {
+                               unsigned short *tmp_buf = (unsigned short *)con_buf0;
+
+                               p -= HEADER_SIZE;
+                               p /= 2;
+                               col = p % maxcol;
+
+                               org = screen_pos(vc, p, viewed);
+                               p += maxcol - col;
+
+                               /* Buffer has even length, so we can always copy
+                                * character + attribute. We do not copy last byte
+                                * to userspace if this_round is odd.
+                                */
+                               this_round = (this_round + 1) >> 1;
+
+                               while (this_round) {
+                                       *tmp_buf++ = vcs_scr_readw(vc, org++);
+                                       this_round --;
+                                       if (++col == maxcol) {
+                                               org = screen_pos(vc, p, viewed);
+                                               col = 0;
+                                               p += maxcol;
+                                       }
+                               }
+                       }
+               }
+
+               /* Finally, release the console semaphore while we push
+                * all the data to userspace from our temporary buffer.
+                *
+                * AKPM: Even though it's a semaphore, we should drop it because
+                * the pagefault handling code may want to call printk().
+                */
+
+               release_console_sem();
+               ret = copy_to_user(buf, con_buf_start, orig_count);
+               acquire_console_sem();
+
+               if (ret) {
+                       read += (orig_count - ret);
+                       ret = -EFAULT;
+                       break;
+               }
+               buf += orig_count;
+               pos += orig_count;
+               read += orig_count;
+               count -= orig_count;
+       }
+       *ppos += read;
+       if (read)
+               ret = read;
+unlock_out:
+       release_console_sem();
+       mutex_unlock(&con_buf_mtx);
+       return ret;
+}
+
+static ssize_t
+vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       unsigned int currcons = iminor(inode);
+       struct vc_data *vc;
+       long pos;
+       long viewed, attr, size, written;
+       char *con_buf0;
+       int col, maxcol;
+       u16 *org0 = NULL, *org = NULL;
+       size_t ret;
+
+       mutex_lock(&con_buf_mtx);
+
+       pos = *ppos;
+
+       /* Select the proper current console and verify
+        * sanity of the situation under the console lock.
+        */
+       acquire_console_sem();
+
+       attr = (currcons & 128);
+       currcons = (currcons & 127);
+
+       if (currcons == 0) {
+               currcons = fg_console;
+               viewed = 1;
+       } else {
+               currcons--;
+               viewed = 0;
+       }
+       ret = -ENXIO;
+       if (!vc_cons_allocated(currcons))
+               goto unlock_out;
+       vc = vc_cons[currcons].d;
+
+       size = vcs_size(inode);
+       ret = -EINVAL;
+       if (pos < 0 || pos > size)
+               goto unlock_out;
+       if (count > size - pos)
+               count = size - pos;
+       written = 0;
+       while (count) {
+               long this_round = count;
+               size_t orig_count;
+               long p;
+
+               if (this_round > CON_BUF_SIZE)
+                       this_round = CON_BUF_SIZE;
+
+               /* Temporarily drop the console lock so that we can read
+                * in the write data from userspace safely.
+                */
+               release_console_sem();
+               ret = copy_from_user(con_buf, buf, this_round);
+               acquire_console_sem();
+
+               if (ret) {
+                       this_round -= ret;
+                       if (!this_round) {
+                               /* Abort loop if no data were copied. Otherwise
+                                * fail with -EFAULT.
+                                */
+                               if (written)
+                                       break;
+                               ret = -EFAULT;
+                               goto unlock_out;
+                       }
+               }
+
+               /* The vcs_size might have changed while we slept to grab
+                * the user buffer, so recheck.
+                * Return data written up to now on failure.
+                */
+               size = vcs_size(inode);
+               if (pos >= size)
+                       break;
+               if (this_round > size - pos)
+                       this_round = size - pos;
+
+               /* OK, now actually push the write to the console
+                * under the lock using the local kernel buffer.
+                */
+
+               con_buf0 = con_buf;
+               orig_count = this_round;
+               maxcol = vc->vc_cols;
+               p = pos;
+               if (!attr) {
+                       org0 = org = screen_pos(vc, p, viewed);
+                       col = p % maxcol;
+                       p += maxcol - col;
+
+                       while (this_round > 0) {
+                               unsigned char c = *con_buf0++;
+
+                               this_round--;
+                               vcs_scr_writew(vc,
+                                              (vcs_scr_readw(vc, org) & 0xff00) | c, org);
+                               org++;
+                               if (++col == maxcol) {
+                                       org = screen_pos(vc, p, viewed);
+                                       col = 0;
+                                       p += maxcol;
+                               }
+                       }
+               } else {
+                       if (p < HEADER_SIZE) {
+                               char header[HEADER_SIZE];
+
+                               getconsxy(vc, header + 2);
+                               while (p < HEADER_SIZE && this_round > 0) {
+                                       this_round--;
+                                       header[p++] = *con_buf0++;
+                               }
+                               if (!viewed)
+                                       putconsxy(vc, header + 2);
+                       }
+                       p -= HEADER_SIZE;
+                       col = (p/2) % maxcol;
+                       if (this_round > 0) {
+                               org0 = org = screen_pos(vc, p/2, viewed);
+                               if ((p & 1) && this_round > 0) {
+                                       char c;
+
+                                       this_round--;
+                                       c = *con_buf0++;
+#ifdef __BIG_ENDIAN
+                                       vcs_scr_writew(vc, c |
+                                            (vcs_scr_readw(vc, org) & 0xff00), org);
+#else
+                                       vcs_scr_writew(vc, (c << 8) |
+                                            (vcs_scr_readw(vc, org) & 0xff), org);
+#endif
+                                       org++;
+                                       p++;
+                                       if (++col == maxcol) {
+                                               org = screen_pos(vc, p/2, viewed);
+                                               col = 0;
+                                       }
+                               }
+                               p /= 2;
+                               p += maxcol - col;
+                       }
+                       while (this_round > 1) {
+                               unsigned short w;
+
+                               w = get_unaligned(((unsigned short *)con_buf0));
+                               vcs_scr_writew(vc, w, org++);
+                               con_buf0 += 2;
+                               this_round -= 2;
+                               if (++col == maxcol) {
+                                       org = screen_pos(vc, p, viewed);
+                                       col = 0;
+                                       p += maxcol;
+                               }
+                       }
+                       if (this_round > 0) {
+                               unsigned char c;
+
+                               c = *con_buf0++;
+#ifdef __BIG_ENDIAN
+                               vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff) | (c << 8), org);
+#else
+                               vcs_scr_writew(vc, (vcs_scr_readw(vc, org) & 0xff00) | c, org);
+#endif
+                       }
+               }
+               count -= orig_count;
+               written += orig_count;
+               buf += orig_count;
+               pos += orig_count;
+               if (org0)
+                       update_region(vc, (unsigned long)(org0), org - org0);
+       }
+       *ppos += written;
+       ret = written;
+       if (written)
+               vcs_scr_updated(vc);
+
+unlock_out:
+       release_console_sem();
+
+       mutex_unlock(&con_buf_mtx);
+
+       return ret;
+}
+
+static unsigned int
+vcs_poll(struct file *file, poll_table *wait)
+{
+       struct vcs_poll_data *poll = vcs_poll_data_get(file);
+       int ret = 0;
+
+       if (poll) {
+               poll_wait(file, &poll->waitq, wait);
+               if (!poll->seen_last_update)
+                       ret = POLLIN | POLLRDNORM;
+       }
+       return ret;
+}
+
+static int
+vcs_fasync(int fd, struct file *file, int on)
+{
+       struct vcs_poll_data *poll = file->private_data;
+
+       if (!poll) {
+               /* don't allocate anything if all we want is disable fasync */
+               if (!on)
+                       return 0;
+               poll = vcs_poll_data_get(file);
+               if (!poll)
+                       return -ENOMEM;
+       }
+
+       return fasync_helper(fd, file, on, &poll->fasync);
+}
+
+static int
+vcs_open(struct inode *inode, struct file *filp)
+{
+       unsigned int currcons = iminor(inode) & 127;
+       int ret = 0;
+       
+       tty_lock();
+       if(currcons && !vc_cons_allocated(currcons-1))
+               ret = -ENXIO;
+       tty_unlock();
+       return ret;
+}
+
+static int vcs_release(struct inode *inode, struct file *file)
+{
+       struct vcs_poll_data *poll = file->private_data;
+
+       if (poll)
+               vcs_poll_data_free(poll);
+       return 0;
+}
+
+static const struct file_operations vcs_fops = {
+       .llseek         = vcs_lseek,
+       .read           = vcs_read,
+       .write          = vcs_write,
+       .poll           = vcs_poll,
+       .fasync         = vcs_fasync,
+       .open           = vcs_open,
+       .release        = vcs_release,
+};
+
+static struct class *vc_class;
+
+void vcs_make_sysfs(int index)
+{
+       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 1), NULL,
+                     "vcs%u", index + 1);
+       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, index + 129), NULL,
+                     "vcsa%u", index + 1);
+}
+
+void vcs_remove_sysfs(int index)
+{
+       device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 1));
+       device_destroy(vc_class, MKDEV(VCS_MAJOR, index + 129));
+}
+
+int __init vcs_init(void)
+{
+       unsigned int i;
+
+       if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops))
+               panic("unable to get major %d for vcs device", VCS_MAJOR);
+       vc_class = class_create(THIS_MODULE, "vc");
+
+       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs");
+       device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa");
+       for (i = 0; i < MIN_NR_CONSOLES; i++)
+               vcs_make_sysfs(i);
+       return 0;
+}
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
new file mode 100644 (file)
index 0000000..a8ec48e
--- /dev/null
@@ -0,0 +1,4209 @@
+/*
+ *  linux/drivers/char/vt.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+/*
+ * Hopefully this will be a rather complete VT102 implementation.
+ *
+ * Beeping thanks to John T Kohl.
+ *
+ * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
+ *   Chars, and VT100 enhancements by Peter MacDonald.
+ *
+ * Copy and paste function by Andrew Haylett,
+ *   some enhancements by Alessandro Rubini.
+ *
+ * Code to check for different video-cards mostly by Galen Hunt,
+ * <g-hunt@ee.utah.edu>
+ *
+ * Rudimentary ISO 10646/Unicode/UTF-8 character set support by
+ * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>.
+ *
+ * Dynamic allocation of consoles, aeb@cwi.nl, May 1994
+ * Resizing of consoles, aeb, 940926
+ *
+ * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94
+ * <poe@daimi.aau.dk>
+ *
+ * User-defined bell sound, new setterm control sequences and printk
+ * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95
+ *
+ * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp>
+ *
+ * Merge with the abstract console driver by Geert Uytterhoeven
+ * <geert@linux-m68k.org>, Jan 1997.
+ *
+ *   Original m68k console driver modifications by
+ *
+ *     - Arno Griffioen <arno@usn.nl>
+ *     - David Carter <carter@cs.bris.ac.uk>
+ * 
+ *   The abstract console driver provides a generic interface for a text
+ *   console. It supports VGA text mode, frame buffer based graphical consoles
+ *   and special graphics processors that are only accessible through some
+ *   registers (e.g. a TMS340x0 GSP).
+ *
+ *   The interface to the hardware is specified using a special structure
+ *   (struct consw) which contains function pointers to console operations
+ *   (see <linux/console.h> for more information).
+ *
+ * Support for changeable cursor shape
+ * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>, August 1997
+ *
+ * Ported to i386 and con_scrolldelta fixed
+ * by Emmanuel Marty <core@ggi-project.org>, April 1998
+ *
+ * Resurrected character buffers in videoram plus lots of other trickery
+ * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998
+ *
+ * Removed old-style timers, introduced console_timer, made timer
+ * deletion SMP-safe.  17Jun00, Andrew Morton
+ *
+ * Removed console_lock, enabled interrupts across all console operations
+ * 13 March 2001, Andrew Morton
+ *
+ * Fixed UTF-8 mode so alternate charset modes always work according
+ * to control sequences interpreted in do_con_trol function
+ * preserving backward VT100 semigraphics compatibility,
+ * malformed UTF sequences represented as sequences of replacement glyphs,
+ * original codes or '?' as a last resort if replacement glyph is undefined
+ * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kd.h>
+#include <linux/slab.h>
+#include <linux/major.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/smp_lock.h>
+#include <linux/tiocl.h>
+#include <linux/kbd_kern.h>
+#include <linux/consolemap.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/pm.h>
+#include <linux/font.h>
+#include <linux/bitops.h>
+#include <linux/notifier.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <asm/system.h>
+#include <linux/uaccess.h>
+#include <linux/kdb.h>
+#include <linux/ctype.h>
+
+#define MAX_NR_CON_DRIVER 16
+
+#define CON_DRIVER_FLAG_MODULE 1
+#define CON_DRIVER_FLAG_INIT   2
+#define CON_DRIVER_FLAG_ATTR   4
+
+struct con_driver {
+       const struct consw *con;
+       const char *desc;
+       struct device *dev;
+       int node;
+       int first;
+       int last;
+       int flag;
+};
+
+static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER];
+const struct consw *conswitchp;
+
+/* A bitmap for codes <32. A bit of 1 indicates that the code
+ * corresponding to that bit number invokes some special action
+ * (such as cursor movement) and should not be displayed as a
+ * glyph unless the disp_ctrl mode is explicitly enabled.
+ */
+#define CTRL_ACTION 0x0d00ff81
+#define CTRL_ALWAYS 0x0800f501 /* Cannot be overridden by disp_ctrl */
+
+/*
+ * Here is the default bell parameters: 750HZ, 1/8th of a second
+ */
+#define DEFAULT_BELL_PITCH     750
+#define DEFAULT_BELL_DURATION  (HZ/8)
+
+struct vc vc_cons [MAX_NR_CONSOLES];
+
+#ifndef VT_SINGLE_DRIVER
+static const struct consw *con_driver_map[MAX_NR_CONSOLES];
+#endif
+
+static int con_open(struct tty_struct *, struct file *);
+static void vc_init(struct vc_data *vc, unsigned int rows,
+                   unsigned int cols, int do_clear);
+static void gotoxy(struct vc_data *vc, int new_x, int new_y);
+static void save_cur(struct vc_data *vc);
+static void reset_terminal(struct vc_data *vc, int do_clear);
+static void con_flush_chars(struct tty_struct *tty);
+static int set_vesa_blanking(char __user *p);
+static void set_cursor(struct vc_data *vc);
+static void hide_cursor(struct vc_data *vc);
+static void console_callback(struct work_struct *ignored);
+static void blank_screen_t(unsigned long dummy);
+static void set_palette(struct vc_data *vc);
+
+static int printable;          /* Is console ready for printing? */
+int default_utf8 = true;
+module_param(default_utf8, int, S_IRUGO | S_IWUSR);
+int global_cursor_default = -1;
+module_param(global_cursor_default, int, S_IRUGO | S_IWUSR);
+
+static int cur_default = CUR_DEFAULT;
+module_param(cur_default, int, S_IRUGO | S_IWUSR);
+
+/*
+ * ignore_poke: don't unblank the screen when things are typed.  This is
+ * mainly for the privacy of braille terminal users.
+ */
+static int ignore_poke;
+
+int do_poke_blanked_console;
+int console_blanked;
+
+static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
+static int vesa_off_interval;
+static int blankinterval = 10*60;
+core_param(consoleblank, blankinterval, int, 0444);
+
+static DECLARE_WORK(console_work, console_callback);
+
+/*
+ * fg_console is the current virtual console,
+ * last_console is the last used one,
+ * want_console is the console we want to switch to,
+ * saved_* variants are for save/restore around kernel debugger enter/leave
+ */
+int fg_console;
+int last_console;
+int want_console = -1;
+static int saved_fg_console;
+static int saved_last_console;
+static int saved_want_console;
+static int saved_vc_mode;
+static int saved_console_blanked;
+
+/*
+ * For each existing display, we have a pointer to console currently visible
+ * on that display, allowing consoles other than fg_console to be refreshed
+ * appropriately. Unless the low-level driver supplies its own display_fg
+ * variable, we use this one for the "master display".
+ */
+static struct vc_data *master_display_fg;
+
+/*
+ * Unfortunately, we need to delay tty echo when we're currently writing to the
+ * console since the code is (and always was) not re-entrant, so we schedule
+ * all flip requests to process context with schedule-task() and run it from
+ * console_callback().
+ */
+
+/*
+ * For the same reason, we defer scrollback to the console callback.
+ */
+static int scrollback_delta;
+
+/*
+ * Hook so that the power management routines can (un)blank
+ * the console on our behalf.
+ */
+int (*console_blank_hook)(int);
+
+static DEFINE_TIMER(console_timer, blank_screen_t, 0, 0);
+static int blank_state;
+static int blank_timer_expired;
+enum {
+       blank_off = 0,
+       blank_normal_wait,
+       blank_vesa_wait,
+};
+
+/*
+ * Notifier list for console events.
+ */
+static ATOMIC_NOTIFIER_HEAD(vt_notifier_list);
+
+int register_vt_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_register(&vt_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(register_vt_notifier);
+
+int unregister_vt_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_unregister(&vt_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_vt_notifier);
+
+static void notify_write(struct vc_data *vc, unsigned int unicode)
+{
+       struct vt_notifier_param param = { .vc = vc, unicode = unicode };
+       atomic_notifier_call_chain(&vt_notifier_list, VT_WRITE, &param);
+}
+
+static void notify_update(struct vc_data *vc)
+{
+       struct vt_notifier_param param = { .vc = vc };
+       atomic_notifier_call_chain(&vt_notifier_list, VT_UPDATE, &param);
+}
+/*
+ *     Low-Level Functions
+ */
+
+#define IS_FG(vc)      ((vc)->vc_num == fg_console)
+
+#ifdef VT_BUF_VRAM_ONLY
+#define DO_UPDATE(vc)  0
+#else
+#define DO_UPDATE(vc)  (CON_IS_VISIBLE(vc) && !console_blanked)
+#endif
+
+static inline unsigned short *screenpos(struct vc_data *vc, int offset, int viewed)
+{
+       unsigned short *p;
+       
+       if (!viewed)
+               p = (unsigned short *)(vc->vc_origin + offset);
+       else if (!vc->vc_sw->con_screen_pos)
+               p = (unsigned short *)(vc->vc_visible_origin + offset);
+       else
+               p = vc->vc_sw->con_screen_pos(vc, offset);
+       return p;
+}
+
+/* Called  from the keyboard irq path.. */
+static inline void scrolldelta(int lines)
+{
+       /* FIXME */
+       /* scrolldelta needs some kind of consistency lock, but the BKL was
+          and still is not protecting versus the scheduled back end */
+       scrollback_delta += lines;
+       schedule_console_callback();
+}
+
+void schedule_console_callback(void)
+{
+       schedule_work(&console_work);
+}
+
+static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
+{
+       unsigned short *d, *s;
+
+       if (t+nr >= b)
+               nr = b - t - 1;
+       if (b > vc->vc_rows || t >= b || nr < 1)
+               return;
+       if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_UP, nr))
+               return;
+       d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
+       s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
+       scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
+       scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char,
+                   vc->vc_size_row * nr);
+}
+
+static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
+{
+       unsigned short *s;
+       unsigned int step;
+
+       if (t+nr >= b)
+               nr = b - t - 1;
+       if (b > vc->vc_rows || t >= b || nr < 1)
+               return;
+       if (CON_IS_VISIBLE(vc) && vc->vc_sw->con_scroll(vc, t, b, SM_DOWN, nr))
+               return;
+       s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
+       step = vc->vc_cols * nr;
+       scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row);
+       scr_memsetw(s, vc->vc_video_erase_char, 2 * step);
+}
+
+static void do_update_region(struct vc_data *vc, unsigned long start, int count)
+{
+#ifndef VT_BUF_VRAM_ONLY
+       unsigned int xx, yy, offset;
+       u16 *p;
+
+       p = (u16 *) start;
+       if (!vc->vc_sw->con_getxy) {
+               offset = (start - vc->vc_origin) / 2;
+               xx = offset % vc->vc_cols;
+               yy = offset / vc->vc_cols;
+       } else {
+               int nxx, nyy;
+               start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy);
+               xx = nxx; yy = nyy;
+       }
+       for(;;) {
+               u16 attrib = scr_readw(p) & 0xff00;
+               int startx = xx;
+               u16 *q = p;
+               while (xx < vc->vc_cols && count) {
+                       if (attrib != (scr_readw(p) & 0xff00)) {
+                               if (p > q)
+                                       vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
+                               startx = xx;
+                               q = p;
+                               attrib = scr_readw(p) & 0xff00;
+                       }
+                       p++;
+                       xx++;
+                       count--;
+               }
+               if (p > q)
+                       vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
+               if (!count)
+                       break;
+               xx = 0;
+               yy++;
+               if (vc->vc_sw->con_getxy) {
+                       p = (u16 *)start;
+                       start = vc->vc_sw->con_getxy(vc, start, NULL, NULL);
+               }
+       }
+#endif
+}
+
+void update_region(struct vc_data *vc, unsigned long start, int count)
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       if (DO_UPDATE(vc)) {
+               hide_cursor(vc);
+               do_update_region(vc, start, count);
+               set_cursor(vc);
+       }
+}
+
+/* Structure of attributes is hardware-dependent */
+
+static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
+    u8 _underline, u8 _reverse, u8 _italic)
+{
+       if (vc->vc_sw->con_build_attr)
+               return vc->vc_sw->con_build_attr(vc, _color, _intensity,
+                      _blink, _underline, _reverse, _italic);
+
+#ifndef VT_BUF_VRAM_ONLY
+/*
+ * ++roman: I completely changed the attribute format for monochrome
+ * mode (!can_do_color). The formerly used MDA (monochrome display
+ * adapter) format didn't allow the combination of certain effects.
+ * Now the attribute is just a bit vector:
+ *  Bit 0..1: intensity (0..2)
+ *  Bit 2   : underline
+ *  Bit 3   : reverse
+ *  Bit 7   : blink
+ */
+       {
+       u8 a = _color;
+       if (!vc->vc_can_do_color)
+               return _intensity |
+                      (_italic ? 2 : 0) |
+                      (_underline ? 4 : 0) |
+                      (_reverse ? 8 : 0) |
+                      (_blink ? 0x80 : 0);
+       if (_italic)
+               a = (a & 0xF0) | vc->vc_itcolor;
+       else if (_underline)
+               a = (a & 0xf0) | vc->vc_ulcolor;
+       else if (_intensity == 0)
+               a = (a & 0xf0) | vc->vc_ulcolor;
+       if (_reverse)
+               a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
+       if (_blink)
+               a ^= 0x80;
+       if (_intensity == 2)
+               a ^= 0x08;
+       if (vc->vc_hi_font_mask == 0x100)
+               a <<= 1;
+       return a;
+       }
+#else
+       return 0;
+#endif
+}
+
+static void update_attr(struct vc_data *vc)
+{
+       vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity,
+                     vc->vc_blink, vc->vc_underline,
+                     vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
+       vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
+}
+
+/* Note: inverting the screen twice should revert to the original state */
+void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
+{
+       unsigned short *p;
+
+       WARN_CONSOLE_UNLOCKED();
+
+       count /= 2;
+       p = screenpos(vc, offset, viewed);
+       if (vc->vc_sw->con_invert_region)
+               vc->vc_sw->con_invert_region(vc, p, count);
+#ifndef VT_BUF_VRAM_ONLY
+       else {
+               u16 *q = p;
+               int cnt = count;
+               u16 a;
+
+               if (!vc->vc_can_do_color) {
+                       while (cnt--) {
+                           a = scr_readw(q);
+                           a ^= 0x0800;
+                           scr_writew(a, q);
+                           q++;
+                       }
+               } else if (vc->vc_hi_font_mask == 0x100) {
+                       while (cnt--) {
+                               a = scr_readw(q);
+                               a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
+                               scr_writew(a, q);
+                               q++;
+                       }
+               } else {
+                       while (cnt--) {
+                               a = scr_readw(q);
+                               a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
+                               scr_writew(a, q);
+                               q++;
+                       }
+               }
+       }
+#endif
+       if (DO_UPDATE(vc))
+               do_update_region(vc, (unsigned long) p, count);
+}
+
+/* used by selection: complement pointer position */
+void complement_pos(struct vc_data *vc, int offset)
+{
+       static int old_offset = -1;
+       static unsigned short old;
+       static unsigned short oldx, oldy;
+
+       WARN_CONSOLE_UNLOCKED();
+
+       if (old_offset != -1 && old_offset >= 0 &&
+           old_offset < vc->vc_screenbuf_size) {
+               scr_writew(old, screenpos(vc, old_offset, 1));
+               if (DO_UPDATE(vc))
+                       vc->vc_sw->con_putc(vc, old, oldy, oldx);
+       }
+
+       old_offset = offset;
+
+       if (offset != -1 && offset >= 0 &&
+           offset < vc->vc_screenbuf_size) {
+               unsigned short new;
+               unsigned short *p;
+               p = screenpos(vc, offset, 1);
+               old = scr_readw(p);
+               new = old ^ vc->vc_complement_mask;
+               scr_writew(new, p);
+               if (DO_UPDATE(vc)) {
+                       oldx = (offset >> 1) % vc->vc_cols;
+                       oldy = (offset >> 1) / vc->vc_cols;
+                       vc->vc_sw->con_putc(vc, new, oldy, oldx);
+               }
+       }
+
+}
+
+static void insert_char(struct vc_data *vc, unsigned int nr)
+{
+       unsigned short *p, *q = (unsigned short *)vc->vc_pos;
+
+       p = q + vc->vc_cols - nr - vc->vc_x;
+       while (--p >= q)
+               scr_writew(scr_readw(p), p + nr);
+       scr_memsetw(q, vc->vc_video_erase_char, nr * 2);
+       vc->vc_need_wrap = 0;
+       if (DO_UPDATE(vc)) {
+               unsigned short oldattr = vc->vc_attr;
+               vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1,
+                                    vc->vc_cols - vc->vc_x - nr);
+               vc->vc_attr = vc->vc_video_erase_char >> 8;
+               while (nr--)
+                       vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr);
+               vc->vc_attr = oldattr;
+       }
+}
+
+static void delete_char(struct vc_data *vc, unsigned int nr)
+{
+       unsigned int i = vc->vc_x;
+       unsigned short *p = (unsigned short *)vc->vc_pos;
+
+       while (++i <= vc->vc_cols - nr) {
+               scr_writew(scr_readw(p+nr), p);
+               p++;
+       }
+       scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
+       vc->vc_need_wrap = 0;
+       if (DO_UPDATE(vc)) {
+               unsigned short oldattr = vc->vc_attr;
+               vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1,
+                                    vc->vc_cols - vc->vc_x - nr);
+               vc->vc_attr = vc->vc_video_erase_char >> 8;
+               while (nr--)
+                       vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y,
+                                    vc->vc_cols - 1 - nr);
+               vc->vc_attr = oldattr;
+       }
+}
+
+static int softcursor_original;
+
+static void add_softcursor(struct vc_data *vc)
+{
+       int i = scr_readw((u16 *) vc->vc_pos);
+       u32 type = vc->vc_cursor_type;
+
+       if (! (type & 0x10)) return;
+       if (softcursor_original != -1) return;
+       softcursor_original = i;
+       i |= ((type >> 8) & 0xff00 );
+       i ^= ((type) & 0xff00 );
+       if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
+       if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
+       scr_writew(i, (u16 *) vc->vc_pos);
+       if (DO_UPDATE(vc))
+               vc->vc_sw->con_putc(vc, i, vc->vc_y, vc->vc_x);
+}
+
+static void hide_softcursor(struct vc_data *vc)
+{
+       if (softcursor_original != -1) {
+               scr_writew(softcursor_original, (u16 *)vc->vc_pos);
+               if (DO_UPDATE(vc))
+                       vc->vc_sw->con_putc(vc, softcursor_original,
+                                       vc->vc_y, vc->vc_x);
+               softcursor_original = -1;
+       }
+}
+
+static void hide_cursor(struct vc_data *vc)
+{
+       if (vc == sel_cons)
+               clear_selection();
+       vc->vc_sw->con_cursor(vc, CM_ERASE);
+       hide_softcursor(vc);
+}
+
+static void set_cursor(struct vc_data *vc)
+{
+       if (!IS_FG(vc) || console_blanked ||
+           vc->vc_mode == KD_GRAPHICS)
+               return;
+       if (vc->vc_deccm) {
+               if (vc == sel_cons)
+                       clear_selection();
+               add_softcursor(vc);
+               if ((vc->vc_cursor_type & 0x0f) != 1)
+                       vc->vc_sw->con_cursor(vc, CM_DRAW);
+       } else
+               hide_cursor(vc);
+}
+
+static void set_origin(struct vc_data *vc)
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       if (!CON_IS_VISIBLE(vc) ||
+           !vc->vc_sw->con_set_origin ||
+           !vc->vc_sw->con_set_origin(vc))
+               vc->vc_origin = (unsigned long)vc->vc_screenbuf;
+       vc->vc_visible_origin = vc->vc_origin;
+       vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
+       vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
+}
+
+static inline void save_screen(struct vc_data *vc)
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       if (vc->vc_sw->con_save_screen)
+               vc->vc_sw->con_save_screen(vc);
+}
+
+/*
+ *     Redrawing of screen
+ */
+
+static void clear_buffer_attributes(struct vc_data *vc)
+{
+       unsigned short *p = (unsigned short *)vc->vc_origin;
+       int count = vc->vc_screenbuf_size / 2;
+       int mask = vc->vc_hi_font_mask | 0xff;
+
+       for (; count > 0; count--, p++) {
+               scr_writew((scr_readw(p)&mask) | (vc->vc_video_erase_char & ~mask), p);
+       }
+}
+
+void redraw_screen(struct vc_data *vc, int is_switch)
+{
+       int redraw = 0;
+
+       WARN_CONSOLE_UNLOCKED();
+
+       if (!vc) {
+               /* strange ... */
+               /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */
+               return;
+       }
+
+       if (is_switch) {
+               struct vc_data *old_vc = vc_cons[fg_console].d;
+               if (old_vc == vc)
+                       return;
+               if (!CON_IS_VISIBLE(vc))
+                       redraw = 1;
+               *vc->vc_display_fg = vc;
+               fg_console = vc->vc_num;
+               hide_cursor(old_vc);
+               if (!CON_IS_VISIBLE(old_vc)) {
+                       save_screen(old_vc);
+                       set_origin(old_vc);
+               }
+       } else {
+               hide_cursor(vc);
+               redraw = 1;
+       }
+
+       if (redraw) {
+               int update;
+               int old_was_color = vc->vc_can_do_color;
+
+               set_origin(vc);
+               update = vc->vc_sw->con_switch(vc);
+               set_palette(vc);
+               /*
+                * If console changed from mono<->color, the best we can do
+                * is to clear the buffer attributes. As it currently stands,
+                * rebuilding new attributes from the old buffer is not doable
+                * without overly complex code.
+                */
+               if (old_was_color != vc->vc_can_do_color) {
+                       update_attr(vc);
+                       clear_buffer_attributes(vc);
+               }
+
+               /* Forcibly update if we're panicing */
+               if ((update && vc->vc_mode != KD_GRAPHICS) ||
+                   vt_force_oops_output(vc))
+                       do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
+       }
+       set_cursor(vc);
+       if (is_switch) {
+               set_leds();
+               compute_shiftstate();
+               notify_update(vc);
+       }
+}
+
+/*
+ *     Allocation, freeing and resizing of VTs.
+ */
+
+int vc_cons_allocated(unsigned int i)
+{
+       return (i < MAX_NR_CONSOLES && vc_cons[i].d);
+}
+
+static void visual_init(struct vc_data *vc, int num, int init)
+{
+       /* ++Geert: vc->vc_sw->con_init determines console size */
+       if (vc->vc_sw)
+               module_put(vc->vc_sw->owner);
+       vc->vc_sw = conswitchp;
+#ifndef VT_SINGLE_DRIVER
+       if (con_driver_map[num])
+               vc->vc_sw = con_driver_map[num];
+#endif
+       __module_get(vc->vc_sw->owner);
+       vc->vc_num = num;
+       vc->vc_display_fg = &master_display_fg;
+       vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
+       vc->vc_uni_pagedir = 0;
+       vc->vc_hi_font_mask = 0;
+       vc->vc_complement_mask = 0;
+       vc->vc_can_do_color = 0;
+       vc->vc_panic_force_write = false;
+       vc->vc_sw->con_init(vc, init);
+       if (!vc->vc_complement_mask)
+               vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
+       vc->vc_s_complement_mask = vc->vc_complement_mask;
+       vc->vc_size_row = vc->vc_cols << 1;
+       vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
+}
+
+int vc_allocate(unsigned int currcons) /* return 0 on success */
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       if (currcons >= MAX_NR_CONSOLES)
+               return -ENXIO;
+       if (!vc_cons[currcons].d) {
+           struct vc_data *vc;
+           struct vt_notifier_param param;
+
+           /* prevent users from taking too much memory */
+           if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
+             return -EPERM;
+
+           /* due to the granularity of kmalloc, we waste some memory here */
+           /* the alloc is done in two steps, to optimize the common situation
+              of a 25x80 console (structsize=216, screenbuf_size=4000) */
+           /* although the numbers above are not valid since long ago, the
+              point is still up-to-date and the comment still has its value
+              even if only as a historical artifact.  --mj, July 1998 */
+           param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
+           if (!vc)
+               return -ENOMEM;
+           vc_cons[currcons].d = vc;
+           tty_port_init(&vc->port);
+           INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
+           visual_init(vc, currcons, 1);
+           if (!*vc->vc_uni_pagedir_loc)
+               con_set_default_unimap(vc);
+           vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
+           if (!vc->vc_screenbuf) {
+               kfree(vc);
+               vc_cons[currcons].d = NULL;
+               return -ENOMEM;
+           }
+
+           /* If no drivers have overridden us and the user didn't pass a
+              boot option, default to displaying the cursor */
+           if (global_cursor_default == -1)
+                   global_cursor_default = 1;
+
+           vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
+           vcs_make_sysfs(currcons);
+           atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
+       }
+       return 0;
+}
+
+static inline int resize_screen(struct vc_data *vc, int width, int height,
+                               int user)
+{
+       /* Resizes the resolution of the display adapater */
+       int err = 0;
+
+       if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_resize)
+               err = vc->vc_sw->con_resize(vc, width, height, user);
+
+       return err;
+}
+
+/*
+ * Change # of rows and columns (0 means unchanged/the size of fg_console)
+ * [this is to be used together with some user program
+ * like resize that changes the hardware videomode]
+ */
+#define VC_RESIZE_MAXCOL (32767)
+#define VC_RESIZE_MAXROW (32767)
+
+/**
+ *     vc_do_resize    -       resizing method for the tty
+ *     @tty: tty being resized
+ *     @real_tty: real tty (different to tty if a pty/tty pair)
+ *     @vc: virtual console private data
+ *     @cols: columns
+ *     @lines: lines
+ *
+ *     Resize a virtual console, clipping according to the actual constraints.
+ *     If the caller passes a tty structure then update the termios winsize
+ *     information and perform any necessary signal handling.
+ *
+ *     Caller must hold the console semaphore. Takes the termios mutex and
+ *     ctrl_lock of the tty IFF a tty is passed.
+ */
+
+static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
+                               unsigned int cols, unsigned int lines)
+{
+       unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
+       unsigned long end;
+       unsigned int old_cols, old_rows, old_row_size, old_screen_size;
+       unsigned int new_cols, new_rows, new_row_size, new_screen_size;
+       unsigned int user;
+       unsigned short *newscreen;
+
+       WARN_CONSOLE_UNLOCKED();
+
+       if (!vc)
+               return -ENXIO;
+
+       user = vc->vc_resize_user;
+       vc->vc_resize_user = 0;
+
+       if (cols > VC_RESIZE_MAXCOL || lines > VC_RESIZE_MAXROW)
+               return -EINVAL;
+
+       new_cols = (cols ? cols : vc->vc_cols);
+       new_rows = (lines ? lines : vc->vc_rows);
+       new_row_size = new_cols << 1;
+       new_screen_size = new_row_size * new_rows;
+
+       if (new_cols == vc->vc_cols && new_rows == vc->vc_rows)
+               return 0;
+
+       newscreen = kmalloc(new_screen_size, GFP_USER);
+       if (!newscreen)
+               return -ENOMEM;
+
+       old_rows = vc->vc_rows;
+       old_cols = vc->vc_cols;
+       old_row_size = vc->vc_size_row;
+       old_screen_size = vc->vc_screenbuf_size;
+
+       err = resize_screen(vc, new_cols, new_rows, user);
+       if (err) {
+               kfree(newscreen);
+               return err;
+       }
+
+       vc->vc_rows = new_rows;
+       vc->vc_cols = new_cols;
+       vc->vc_size_row = new_row_size;
+       vc->vc_screenbuf_size = new_screen_size;
+
+       rlth = min(old_row_size, new_row_size);
+       rrem = new_row_size - rlth;
+       old_origin = vc->vc_origin;
+       new_origin = (long) newscreen;
+       new_scr_end = new_origin + new_screen_size;
+
+       if (vc->vc_y > new_rows) {
+               if (old_rows - vc->vc_y < new_rows) {
+                       /*
+                        * Cursor near the bottom, copy contents from the
+                        * bottom of buffer
+                        */
+                       old_origin += (old_rows - new_rows) * old_row_size;
+               } else {
+                       /*
+                        * Cursor is in no man's land, copy 1/2 screenful
+                        * from the top and bottom of cursor position
+                        */
+                       old_origin += (vc->vc_y - new_rows/2) * old_row_size;
+               }
+       }
+
+       end = old_origin + old_row_size * min(old_rows, new_rows);
+
+       update_attr(vc);
+
+       while (old_origin < end) {
+               scr_memcpyw((unsigned short *) new_origin,
+                           (unsigned short *) old_origin, rlth);
+               if (rrem)
+                       scr_memsetw((void *)(new_origin + rlth),
+                                   vc->vc_video_erase_char, rrem);
+               old_origin += old_row_size;
+               new_origin += new_row_size;
+       }
+       if (new_scr_end > new_origin)
+               scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
+                           new_scr_end - new_origin);
+       kfree(vc->vc_screenbuf);
+       vc->vc_screenbuf = newscreen;
+       vc->vc_screenbuf_size = new_screen_size;
+       set_origin(vc);
+
+       /* do part of a reset_terminal() */
+       vc->vc_top = 0;
+       vc->vc_bottom = vc->vc_rows;
+       gotoxy(vc, vc->vc_x, vc->vc_y);
+       save_cur(vc);
+
+       if (tty) {
+               /* Rewrite the requested winsize data with the actual
+                  resulting sizes */
+               struct winsize ws;
+               memset(&ws, 0, sizeof(ws));
+               ws.ws_row = vc->vc_rows;
+               ws.ws_col = vc->vc_cols;
+               ws.ws_ypixel = vc->vc_scan_lines;
+               tty_do_resize(tty, &ws);
+       }
+
+       if (CON_IS_VISIBLE(vc))
+               update_screen(vc);
+       vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num);
+       return err;
+}
+
+/**
+ *     vc_resize               -       resize a VT
+ *     @vc: virtual console
+ *     @cols: columns
+ *     @rows: rows
+ *
+ *     Resize a virtual console as seen from the console end of things. We
+ *     use the common vc_do_resize methods to update the structures. The
+ *     caller must hold the console sem to protect console internals and
+ *     vc->port.tty
+ */
+
+int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
+{
+       return vc_do_resize(vc->port.tty, vc, cols, rows);
+}
+
+/**
+ *     vt_resize               -       resize a VT
+ *     @tty: tty to resize
+ *     @ws: winsize attributes
+ *
+ *     Resize a virtual terminal. This is called by the tty layer as we
+ *     register our own handler for resizing. The mutual helper does all
+ *     the actual work.
+ *
+ *     Takes the console sem and the called methods then take the tty
+ *     termios_mutex and the tty ctrl_lock in that order.
+ */
+static int vt_resize(struct tty_struct *tty, struct winsize *ws)
+{
+       struct vc_data *vc = tty->driver_data;
+       int ret;
+
+       acquire_console_sem();
+       ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row);
+       release_console_sem();
+       return ret;
+}
+
+void vc_deallocate(unsigned int currcons)
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       if (vc_cons_allocated(currcons)) {
+               struct vc_data *vc = vc_cons[currcons].d;
+               struct vt_notifier_param param = { .vc = vc };
+
+               atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, &param);
+               vcs_remove_sysfs(currcons);
+               vc->vc_sw->con_deinit(vc);
+               put_pid(vc->vt_pid);
+               module_put(vc->vc_sw->owner);
+               kfree(vc->vc_screenbuf);
+               if (currcons >= MIN_NR_CONSOLES)
+                       kfree(vc);
+               vc_cons[currcons].d = NULL;
+       }
+}
+
+/*
+ *     VT102 emulator
+ */
+
+#define set_kbd(vc, x) set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
+#define clr_kbd(vc, x) clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
+#define is_kbd(vc, x)  vc_kbd_mode(kbd_table + (vc)->vc_num, (x))
+
+#define decarm         VC_REPEAT
+#define decckm         VC_CKMODE
+#define kbdapplic      VC_APPLIC
+#define lnm            VC_CRLF
+
+/*
+ * this is what the terminal answers to a ESC-Z or csi0c query.
+ */
+#define VT100ID "\033[?1;2c"
+#define VT102ID "\033[?6c"
+
+unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
+                                      8,12,10,14, 9,13,11,15 };
+
+/* the default colour table, for VGA+ colour systems */
+int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
+    0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
+int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
+    0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
+int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
+    0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
+
+module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR);
+module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR);
+module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR);
+
+/*
+ * gotoxy() must verify all boundaries, because the arguments
+ * might also be negative. If the given position is out of
+ * bounds, the cursor is placed at the nearest margin.
+ */
+static void gotoxy(struct vc_data *vc, int new_x, int new_y)
+{
+       int min_y, max_y;
+
+       if (new_x < 0)
+               vc->vc_x = 0;
+       else {
+               if (new_x >= vc->vc_cols)
+                       vc->vc_x = vc->vc_cols - 1;
+               else
+                       vc->vc_x = new_x;
+       }
+
+       if (vc->vc_decom) {
+               min_y = vc->vc_top;
+               max_y = vc->vc_bottom;
+       } else {
+               min_y = 0;
+               max_y = vc->vc_rows;
+       }
+       if (new_y < min_y)
+               vc->vc_y = min_y;
+       else if (new_y >= max_y)
+               vc->vc_y = max_y - 1;
+       else
+               vc->vc_y = new_y;
+       vc->vc_pos = vc->vc_origin + vc->vc_y * vc->vc_size_row + (vc->vc_x<<1);
+       vc->vc_need_wrap = 0;
+}
+
+/* for absolute user moves, when decom is set */
+static void gotoxay(struct vc_data *vc, int new_x, int new_y)
+{
+       gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y);
+}
+
+void scrollback(struct vc_data *vc, int lines)
+{
+       if (!lines)
+               lines = vc->vc_rows / 2;
+       scrolldelta(-lines);
+}
+
+void scrollfront(struct vc_data *vc, int lines)
+{
+       if (!lines)
+               lines = vc->vc_rows / 2;
+       scrolldelta(lines);
+}
+
+static void lf(struct vc_data *vc)
+{
+       /* don't scroll if above bottom of scrolling region, or
+        * if below scrolling region
+        */
+       if (vc->vc_y + 1 == vc->vc_bottom)
+               scrup(vc, vc->vc_top, vc->vc_bottom, 1);
+       else if (vc->vc_y < vc->vc_rows - 1) {
+               vc->vc_y++;
+               vc->vc_pos += vc->vc_size_row;
+       }
+       vc->vc_need_wrap = 0;
+       notify_write(vc, '\n');
+}
+
+static void ri(struct vc_data *vc)
+{
+       /* don't scroll if below top of scrolling region, or
+        * if above scrolling region
+        */
+       if (vc->vc_y == vc->vc_top)
+               scrdown(vc, vc->vc_top, vc->vc_bottom, 1);
+       else if (vc->vc_y > 0) {
+               vc->vc_y--;
+               vc->vc_pos -= vc->vc_size_row;
+       }
+       vc->vc_need_wrap = 0;
+}
+
+static inline void cr(struct vc_data *vc)
+{
+       vc->vc_pos -= vc->vc_x << 1;
+       vc->vc_need_wrap = vc->vc_x = 0;
+       notify_write(vc, '\r');
+}
+
+static inline void bs(struct vc_data *vc)
+{
+       if (vc->vc_x) {
+               vc->vc_pos -= 2;
+               vc->vc_x--;
+               vc->vc_need_wrap = 0;
+               notify_write(vc, '\b');
+       }
+}
+
+static inline void del(struct vc_data *vc)
+{
+       /* ignored */
+}
+
+static void csi_J(struct vc_data *vc, int vpar)
+{
+       unsigned int count;
+       unsigned short * start;
+
+       switch (vpar) {
+               case 0: /* erase from cursor to end of display */
+                       count = (vc->vc_scr_end - vc->vc_pos) >> 1;
+                       start = (unsigned short *)vc->vc_pos;
+                       if (DO_UPDATE(vc)) {
+                               /* do in two stages */
+                               vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
+                                             vc->vc_cols - vc->vc_x);
+                               vc->vc_sw->con_clear(vc, vc->vc_y + 1, 0,
+                                             vc->vc_rows - vc->vc_y - 1,
+                                             vc->vc_cols);
+                       }
+                       break;
+               case 1: /* erase from start to cursor */
+                       count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
+                       start = (unsigned short *)vc->vc_origin;
+                       if (DO_UPDATE(vc)) {
+                               /* do in two stages */
+                               vc->vc_sw->con_clear(vc, 0, 0, vc->vc_y,
+                                             vc->vc_cols);
+                               vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
+                                             vc->vc_x + 1);
+                       }
+                       break;
+               case 2: /* erase whole display */
+                       count = vc->vc_cols * vc->vc_rows;
+                       start = (unsigned short *)vc->vc_origin;
+                       if (DO_UPDATE(vc))
+                               vc->vc_sw->con_clear(vc, 0, 0,
+                                             vc->vc_rows,
+                                             vc->vc_cols);
+                       break;
+               default:
+                       return;
+       }
+       scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
+       vc->vc_need_wrap = 0;
+}
+
+static void csi_K(struct vc_data *vc, int vpar)
+{
+       unsigned int count;
+       unsigned short * start;
+
+       switch (vpar) {
+               case 0: /* erase from cursor to end of line */
+                       count = vc->vc_cols - vc->vc_x;
+                       start = (unsigned short *)vc->vc_pos;
+                       if (DO_UPDATE(vc))
+                               vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1,
+                                                    vc->vc_cols - vc->vc_x);
+                       break;
+               case 1: /* erase from start of line to cursor */
+                       start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
+                       count = vc->vc_x + 1;
+                       if (DO_UPDATE(vc))
+                               vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
+                                                    vc->vc_x + 1);
+                       break;
+               case 2: /* erase whole line */
+                       start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1));
+                       count = vc->vc_cols;
+                       if (DO_UPDATE(vc))
+                               vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1,
+                                             vc->vc_cols);
+                       break;
+               default:
+                       return;
+       }
+       scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
+       vc->vc_need_wrap = 0;
+}
+
+static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */
+{                                        /* not vt100? */
+       int count;
+
+       if (!vpar)
+               vpar++;
+       count = (vpar > vc->vc_cols - vc->vc_x) ? (vc->vc_cols - vc->vc_x) : vpar;
+
+       scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count);
+       if (DO_UPDATE(vc))
+               vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, count);
+       vc->vc_need_wrap = 0;
+}
+
+static void default_attr(struct vc_data *vc)
+{
+       vc->vc_intensity = 1;
+       vc->vc_italic = 0;
+       vc->vc_underline = 0;
+       vc->vc_reverse = 0;
+       vc->vc_blink = 0;
+       vc->vc_color = vc->vc_def_color;
+}
+
+/* console_sem is held */
+static void csi_m(struct vc_data *vc)
+{
+       int i;
+
+       for (i = 0; i <= vc->vc_npar; i++)
+               switch (vc->vc_par[i]) {
+                       case 0: /* all attributes off */
+                               default_attr(vc);
+                               break;
+                       case 1:
+                               vc->vc_intensity = 2;
+                               break;
+                       case 2:
+                               vc->vc_intensity = 0;
+                               break;
+                       case 3:
+                               vc->vc_italic = 1;
+                               break;
+                       case 4:
+                               vc->vc_underline = 1;
+                               break;
+                       case 5:
+                               vc->vc_blink = 1;
+                               break;
+                       case 7:
+                               vc->vc_reverse = 1;
+                               break;
+                       case 10: /* ANSI X3.64-1979 (SCO-ish?)
+                                 * Select primary font, don't display
+                                 * control chars if defined, don't set
+                                 * bit 8 on output.
+                                 */
+                               vc->vc_translate = set_translate(vc->vc_charset == 0
+                                               ? vc->vc_G0_charset
+                                               : vc->vc_G1_charset, vc);
+                               vc->vc_disp_ctrl = 0;
+                               vc->vc_toggle_meta = 0;
+                               break;
+                       case 11: /* ANSI X3.64-1979 (SCO-ish?)
+                                 * Select first alternate font, lets
+                                 * chars < 32 be displayed as ROM chars.
+                                 */
+                               vc->vc_translate = set_translate(IBMPC_MAP, vc);
+                               vc->vc_disp_ctrl = 1;
+                               vc->vc_toggle_meta = 0;
+                               break;
+                       case 12: /* ANSI X3.64-1979 (SCO-ish?)
+                                 * Select second alternate font, toggle
+                                 * high bit before displaying as ROM char.
+                                 */
+                               vc->vc_translate = set_translate(IBMPC_MAP, vc);
+                               vc->vc_disp_ctrl = 1;
+                               vc->vc_toggle_meta = 1;
+                               break;
+                       case 21:
+                       case 22:
+                               vc->vc_intensity = 1;
+                               break;
+                       case 23:
+                               vc->vc_italic = 0;
+                               break;
+                       case 24:
+                               vc->vc_underline = 0;
+                               break;
+                       case 25:
+                               vc->vc_blink = 0;
+                               break;
+                       case 27:
+                               vc->vc_reverse = 0;
+                               break;
+                       case 38: /* ANSI X3.64-1979 (SCO-ish?)
+                                 * Enables underscore, white foreground
+                                 * with white underscore (Linux - use
+                                 * default foreground).
+                                 */
+                               vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
+                               vc->vc_underline = 1;
+                               break;
+                       case 39: /* ANSI X3.64-1979 (SCO-ish?)
+                                 * Disable underline option.
+                                 * Reset colour to default? It did this
+                                 * before...
+                                 */
+                               vc->vc_color = (vc->vc_def_color & 0x0f) | (vc->vc_color & 0xf0);
+                               vc->vc_underline = 0;
+                               break;
+                       case 49:
+                               vc->vc_color = (vc->vc_def_color & 0xf0) | (vc->vc_color & 0x0f);
+                               break;
+                       default:
+                               if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
+                                       vc->vc_color = color_table[vc->vc_par[i] - 30]
+                                               | (vc->vc_color & 0xf0);
+                               else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47)
+                                       vc->vc_color = (color_table[vc->vc_par[i] - 40] << 4)
+                                               | (vc->vc_color & 0x0f);
+                               break;
+               }
+       update_attr(vc);
+}
+
+static void respond_string(const char *p, struct tty_struct *tty)
+{
+       while (*p) {
+               tty_insert_flip_char(tty, *p, 0);
+               p++;
+       }
+       con_schedule_flip(tty);
+}
+
+static void cursor_report(struct vc_data *vc, struct tty_struct *tty)
+{
+       char buf[40];
+
+       sprintf(buf, "\033[%d;%dR", vc->vc_y + (vc->vc_decom ? vc->vc_top + 1 : 1), vc->vc_x + 1);
+       respond_string(buf, tty);
+}
+
+static inline void status_report(struct tty_struct *tty)
+{
+       respond_string("\033[0n", tty); /* Terminal ok */
+}
+
+static inline void respond_ID(struct tty_struct * tty)
+{
+       respond_string(VT102ID, tty);
+}
+
+void mouse_report(struct tty_struct *tty, int butt, int mrx, int mry)
+{
+       char buf[8];
+
+       sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
+               (char)('!' + mry));
+       respond_string(buf, tty);
+}
+
+/* invoked via ioctl(TIOCLINUX) and through set_selection */
+int mouse_reporting(void)
+{
+       return vc_cons[fg_console].d->vc_report_mouse;
+}
+
+/* console_sem is held */
+static void set_mode(struct vc_data *vc, int on_off)
+{
+       int i;
+
+       for (i = 0; i <= vc->vc_npar; i++)
+               if (vc->vc_ques) {
+                       switch(vc->vc_par[i]) { /* DEC private modes set/reset */
+                       case 1:                 /* Cursor keys send ^[Ox/^[[x */
+                               if (on_off)
+                                       set_kbd(vc, decckm);
+                               else
+                                       clr_kbd(vc, decckm);
+                               break;
+                       case 3: /* 80/132 mode switch unimplemented */
+                               vc->vc_deccolm = on_off;
+#if 0
+                               vc_resize(deccolm ? 132 : 80, vc->vc_rows);
+                               /* this alone does not suffice; some user mode
+                                  utility has to change the hardware regs */
+#endif
+                               break;
+                       case 5:                 /* Inverted screen on/off */
+                               if (vc->vc_decscnm != on_off) {
+                                       vc->vc_decscnm = on_off;
+                                       invert_screen(vc, 0, vc->vc_screenbuf_size, 0);
+                                       update_attr(vc);
+                               }
+                               break;
+                       case 6:                 /* Origin relative/absolute */
+                               vc->vc_decom = on_off;
+                               gotoxay(vc, 0, 0);
+                               break;
+                       case 7:                 /* Autowrap on/off */
+                               vc->vc_decawm = on_off;
+                               break;
+                       case 8:                 /* Autorepeat on/off */
+                               if (on_off)
+                                       set_kbd(vc, decarm);
+                               else
+                                       clr_kbd(vc, decarm);
+                               break;
+                       case 9:
+                               vc->vc_report_mouse = on_off ? 1 : 0;
+                               break;
+                       case 25:                /* Cursor on/off */
+                               vc->vc_deccm = on_off;
+                               break;
+                       case 1000:
+                               vc->vc_report_mouse = on_off ? 2 : 0;
+                               break;
+                       }
+               } else {
+                       switch(vc->vc_par[i]) { /* ANSI modes set/reset */
+                       case 3:                 /* Monitor (display ctrls) */
+                               vc->vc_disp_ctrl = on_off;
+                               break;
+                       case 4:                 /* Insert Mode on/off */
+                               vc->vc_decim = on_off;
+                               break;
+                       case 20:                /* Lf, Enter == CrLf/Lf */
+                               if (on_off)
+                                       set_kbd(vc, lnm);
+                               else
+                                       clr_kbd(vc, lnm);
+                               break;
+                       }
+               }
+}
+
+/* console_sem is held */
+static void setterm_command(struct vc_data *vc)
+{
+       switch(vc->vc_par[0]) {
+               case 1: /* set color for underline mode */
+                       if (vc->vc_can_do_color &&
+                                       vc->vc_par[1] < 16) {
+                               vc->vc_ulcolor = color_table[vc->vc_par[1]];
+                               if (vc->vc_underline)
+                                       update_attr(vc);
+                       }
+                       break;
+               case 2: /* set color for half intensity mode */
+                       if (vc->vc_can_do_color &&
+                                       vc->vc_par[1] < 16) {
+                               vc->vc_halfcolor = color_table[vc->vc_par[1]];
+                               if (vc->vc_intensity == 0)
+                                       update_attr(vc);
+                       }
+                       break;
+               case 8: /* store colors as defaults */
+                       vc->vc_def_color = vc->vc_attr;
+                       if (vc->vc_hi_font_mask == 0x100)
+                               vc->vc_def_color >>= 1;
+                       default_attr(vc);
+                       update_attr(vc);
+                       break;
+               case 9: /* set blanking interval */
+                       blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60;
+                       poke_blanked_console();
+                       break;
+               case 10: /* set bell frequency in Hz */
+                       if (vc->vc_npar >= 1)
+                               vc->vc_bell_pitch = vc->vc_par[1];
+                       else
+                               vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
+                       break;
+               case 11: /* set bell duration in msec */
+                       if (vc->vc_npar >= 1)
+                               vc->vc_bell_duration = (vc->vc_par[1] < 2000) ?
+                                       vc->vc_par[1] * HZ / 1000 : 0;
+                       else
+                               vc->vc_bell_duration = DEFAULT_BELL_DURATION;
+                       break;
+               case 12: /* bring specified console to the front */
+                       if (vc->vc_par[1] >= 1 && vc_cons_allocated(vc->vc_par[1] - 1))
+                               set_console(vc->vc_par[1] - 1);
+                       break;
+               case 13: /* unblank the screen */
+                       poke_blanked_console();
+                       break;
+               case 14: /* set vesa powerdown interval */
+                       vesa_off_interval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ;
+                       break;
+               case 15: /* activate the previous console */
+                       set_console(last_console);
+                       break;
+       }
+}
+
+/* console_sem is held */
+static void csi_at(struct vc_data *vc, unsigned int nr)
+{
+       if (nr > vc->vc_cols - vc->vc_x)
+               nr = vc->vc_cols - vc->vc_x;
+       else if (!nr)
+               nr = 1;
+       insert_char(vc, nr);
+}
+
+/* console_sem is held */
+static void csi_L(struct vc_data *vc, unsigned int nr)
+{
+       if (nr > vc->vc_rows - vc->vc_y)
+               nr = vc->vc_rows - vc->vc_y;
+       else if (!nr)
+               nr = 1;
+       scrdown(vc, vc->vc_y, vc->vc_bottom, nr);
+       vc->vc_need_wrap = 0;
+}
+
+/* console_sem is held */
+static void csi_P(struct vc_data *vc, unsigned int nr)
+{
+       if (nr > vc->vc_cols - vc->vc_x)
+               nr = vc->vc_cols - vc->vc_x;
+       else if (!nr)
+               nr = 1;
+       delete_char(vc, nr);
+}
+
+/* console_sem is held */
+static void csi_M(struct vc_data *vc, unsigned int nr)
+{
+       if (nr > vc->vc_rows - vc->vc_y)
+               nr = vc->vc_rows - vc->vc_y;
+       else if (!nr)
+               nr=1;
+       scrup(vc, vc->vc_y, vc->vc_bottom, nr);
+       vc->vc_need_wrap = 0;
+}
+
+/* console_sem is held (except via vc_init->reset_terminal */
+static void save_cur(struct vc_data *vc)
+{
+       vc->vc_saved_x          = vc->vc_x;
+       vc->vc_saved_y          = vc->vc_y;
+       vc->vc_s_intensity      = vc->vc_intensity;
+       vc->vc_s_italic         = vc->vc_italic;
+       vc->vc_s_underline      = vc->vc_underline;
+       vc->vc_s_blink          = vc->vc_blink;
+       vc->vc_s_reverse        = vc->vc_reverse;
+       vc->vc_s_charset        = vc->vc_charset;
+       vc->vc_s_color          = vc->vc_color;
+       vc->vc_saved_G0         = vc->vc_G0_charset;
+       vc->vc_saved_G1         = vc->vc_G1_charset;
+}
+
+/* console_sem is held */
+static void restore_cur(struct vc_data *vc)
+{
+       gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y);
+       vc->vc_intensity        = vc->vc_s_intensity;
+       vc->vc_italic           = vc->vc_s_italic;
+       vc->vc_underline        = vc->vc_s_underline;
+       vc->vc_blink            = vc->vc_s_blink;
+       vc->vc_reverse          = vc->vc_s_reverse;
+       vc->vc_charset          = vc->vc_s_charset;
+       vc->vc_color            = vc->vc_s_color;
+       vc->vc_G0_charset       = vc->vc_saved_G0;
+       vc->vc_G1_charset       = vc->vc_saved_G1;
+       vc->vc_translate        = set_translate(vc->vc_charset ? vc->vc_G1_charset : vc->vc_G0_charset, vc);
+       update_attr(vc);
+       vc->vc_need_wrap = 0;
+}
+
+enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
+       EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
+       ESpalette };
+
+/* console_sem is held (except via vc_init()) */
+static void reset_terminal(struct vc_data *vc, int do_clear)
+{
+       vc->vc_top              = 0;
+       vc->vc_bottom           = vc->vc_rows;
+       vc->vc_state            = ESnormal;
+       vc->vc_ques             = 0;
+       vc->vc_translate        = set_translate(LAT1_MAP, vc);
+       vc->vc_G0_charset       = LAT1_MAP;
+       vc->vc_G1_charset       = GRAF_MAP;
+       vc->vc_charset          = 0;
+       vc->vc_need_wrap        = 0;
+       vc->vc_report_mouse     = 0;
+       vc->vc_utf              = default_utf8;
+       vc->vc_utf_count        = 0;
+
+       vc->vc_disp_ctrl        = 0;
+       vc->vc_toggle_meta      = 0;
+
+       vc->vc_decscnm          = 0;
+       vc->vc_decom            = 0;
+       vc->vc_decawm           = 1;
+       vc->vc_deccm            = global_cursor_default;
+       vc->vc_decim            = 0;
+
+       set_kbd(vc, decarm);
+       clr_kbd(vc, decckm);
+       clr_kbd(vc, kbdapplic);
+       clr_kbd(vc, lnm);
+       kbd_table[vc->vc_num].lockstate = 0;
+       kbd_table[vc->vc_num].slockstate = 0;
+       kbd_table[vc->vc_num].ledmode = LED_SHOW_FLAGS;
+       kbd_table[vc->vc_num].ledflagstate = kbd_table[vc->vc_num].default_ledflagstate;
+       /* do not do set_leds here because this causes an endless tasklet loop
+          when the keyboard hasn't been initialized yet */
+
+       vc->vc_cursor_type = cur_default;
+       vc->vc_complement_mask = vc->vc_s_complement_mask;
+
+       default_attr(vc);
+       update_attr(vc);
+
+       vc->vc_tab_stop[0]      = 0x01010100;
+       vc->vc_tab_stop[1]      =
+       vc->vc_tab_stop[2]      =
+       vc->vc_tab_stop[3]      =
+       vc->vc_tab_stop[4]      =
+       vc->vc_tab_stop[5]      =
+       vc->vc_tab_stop[6]      =
+       vc->vc_tab_stop[7]      = 0x01010101;
+
+       vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
+       vc->vc_bell_duration = DEFAULT_BELL_DURATION;
+
+       gotoxy(vc, 0, 0);
+       save_cur(vc);
+       if (do_clear)
+           csi_J(vc, 2);
+}
+
+/* console_sem is held */
+static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
+{
+       /*
+        *  Control characters can be used in the _middle_
+        *  of an escape sequence.
+        */
+       switch (c) {
+       case 0:
+               return;
+       case 7:
+               if (vc->vc_bell_duration)
+                       kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration);
+               return;
+       case 8:
+               bs(vc);
+               return;
+       case 9:
+               vc->vc_pos -= (vc->vc_x << 1);
+               while (vc->vc_x < vc->vc_cols - 1) {
+                       vc->vc_x++;
+                       if (vc->vc_tab_stop[vc->vc_x >> 5] & (1 << (vc->vc_x & 31)))
+                               break;
+               }
+               vc->vc_pos += (vc->vc_x << 1);
+               notify_write(vc, '\t');
+               return;
+       case 10: case 11: case 12:
+               lf(vc);
+               if (!is_kbd(vc, lnm))
+                       return;
+       case 13:
+               cr(vc);
+               return;
+       case 14:
+               vc->vc_charset = 1;
+               vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
+               vc->vc_disp_ctrl = 1;
+               return;
+       case 15:
+               vc->vc_charset = 0;
+               vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
+               vc->vc_disp_ctrl = 0;
+               return;
+       case 24: case 26:
+               vc->vc_state = ESnormal;
+               return;
+       case 27:
+               vc->vc_state = ESesc;
+               return;
+       case 127:
+               del(vc);
+               return;
+       case 128+27:
+               vc->vc_state = ESsquare;
+               return;
+       }
+       switch(vc->vc_state) {
+       case ESesc:
+               vc->vc_state = ESnormal;
+               switch (c) {
+               case '[':
+                       vc->vc_state = ESsquare;
+                       return;
+               case ']':
+                       vc->vc_state = ESnonstd;
+                       return;
+               case '%':
+                       vc->vc_state = ESpercent;
+                       return;
+               case 'E':
+                       cr(vc);
+                       lf(vc);
+                       return;
+               case 'M':
+                       ri(vc);
+                       return;
+               case 'D':
+                       lf(vc);
+                       return;
+               case 'H':
+                       vc->vc_tab_stop[vc->vc_x >> 5] |= (1 << (vc->vc_x & 31));
+                       return;
+               case 'Z':
+                       respond_ID(tty);
+                       return;
+               case '7':
+                       save_cur(vc);
+                       return;
+               case '8':
+                       restore_cur(vc);
+                       return;
+               case '(':
+                       vc->vc_state = ESsetG0;
+                       return;
+               case ')':
+                       vc->vc_state = ESsetG1;
+                       return;
+               case '#':
+                       vc->vc_state = EShash;
+                       return;
+               case 'c':
+                       reset_terminal(vc, 1);
+                       return;
+               case '>':  /* Numeric keypad */
+                       clr_kbd(vc, kbdapplic);
+                       return;
+               case '=':  /* Appl. keypad */
+                       set_kbd(vc, kbdapplic);
+                       return;
+               }
+               return;
+       case ESnonstd:
+               if (c=='P') {   /* palette escape sequence */
+                       for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
+                               vc->vc_par[vc->vc_npar] = 0;
+                       vc->vc_npar = 0;
+                       vc->vc_state = ESpalette;
+                       return;
+               } else if (c=='R') {   /* reset palette */
+                       reset_palette(vc);
+                       vc->vc_state = ESnormal;
+               } else
+                       vc->vc_state = ESnormal;
+               return;
+       case ESpalette:
+               if (isxdigit(c)) {
+                       vc->vc_par[vc->vc_npar++] = hex_to_bin(c);
+                       if (vc->vc_npar == 7) {
+                               int i = vc->vc_par[0] * 3, j = 1;
+                               vc->vc_palette[i] = 16 * vc->vc_par[j++];
+                               vc->vc_palette[i++] += vc->vc_par[j++];
+                               vc->vc_palette[i] = 16 * vc->vc_par[j++];
+                               vc->vc_palette[i++] += vc->vc_par[j++];
+                               vc->vc_palette[i] = 16 * vc->vc_par[j++];
+                               vc->vc_palette[i] += vc->vc_par[j];
+                               set_palette(vc);
+                               vc->vc_state = ESnormal;
+                       }
+               } else
+                       vc->vc_state = ESnormal;
+               return;
+       case ESsquare:
+               for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
+                       vc->vc_par[vc->vc_npar] = 0;
+               vc->vc_npar = 0;
+               vc->vc_state = ESgetpars;
+               if (c == '[') { /* Function key */
+                       vc->vc_state=ESfunckey;
+                       return;
+               }
+               vc->vc_ques = (c == '?');
+               if (vc->vc_ques)
+                       return;
+       case ESgetpars:
+               if (c == ';' && vc->vc_npar < NPAR - 1) {
+                       vc->vc_npar++;
+                       return;
+               } else if (c>='0' && c<='9') {
+                       vc->vc_par[vc->vc_npar] *= 10;
+                       vc->vc_par[vc->vc_npar] += c - '0';
+                       return;
+               } else
+                       vc->vc_state = ESgotpars;
+       case ESgotpars:
+               vc->vc_state = ESnormal;
+               switch(c) {
+               case 'h':
+                       set_mode(vc, 1);
+                       return;
+               case 'l':
+                       set_mode(vc, 0);
+                       return;
+               case 'c':
+                       if (vc->vc_ques) {
+                               if (vc->vc_par[0])
+                                       vc->vc_cursor_type = vc->vc_par[0] | (vc->vc_par[1] << 8) | (vc->vc_par[2] << 16);
+                               else
+                                       vc->vc_cursor_type = cur_default;
+                               return;
+                       }
+                       break;
+               case 'm':
+                       if (vc->vc_ques) {
+                               clear_selection();
+                               if (vc->vc_par[0])
+                                       vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1];
+                               else
+                                       vc->vc_complement_mask = vc->vc_s_complement_mask;
+                               return;
+                       }
+                       break;
+               case 'n':
+                       if (!vc->vc_ques) {
+                               if (vc->vc_par[0] == 5)
+                                       status_report(tty);
+                               else if (vc->vc_par[0] == 6)
+                                       cursor_report(vc, tty);
+                       }
+                       return;
+               }
+               if (vc->vc_ques) {
+                       vc->vc_ques = 0;
+                       return;
+               }
+               switch(c) {
+               case 'G': case '`':
+                       if (vc->vc_par[0])
+                               vc->vc_par[0]--;
+                       gotoxy(vc, vc->vc_par[0], vc->vc_y);
+                       return;
+               case 'A':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       gotoxy(vc, vc->vc_x, vc->vc_y - vc->vc_par[0]);
+                       return;
+               case 'B': case 'e':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       gotoxy(vc, vc->vc_x, vc->vc_y + vc->vc_par[0]);
+                       return;
+               case 'C': case 'a':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       gotoxy(vc, vc->vc_x + vc->vc_par[0], vc->vc_y);
+                       return;
+               case 'D':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       gotoxy(vc, vc->vc_x - vc->vc_par[0], vc->vc_y);
+                       return;
+               case 'E':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       gotoxy(vc, 0, vc->vc_y + vc->vc_par[0]);
+                       return;
+               case 'F':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       gotoxy(vc, 0, vc->vc_y - vc->vc_par[0]);
+                       return;
+               case 'd':
+                       if (vc->vc_par[0])
+                               vc->vc_par[0]--;
+                       gotoxay(vc, vc->vc_x ,vc->vc_par[0]);
+                       return;
+               case 'H': case 'f':
+                       if (vc->vc_par[0])
+                               vc->vc_par[0]--;
+                       if (vc->vc_par[1])
+                               vc->vc_par[1]--;
+                       gotoxay(vc, vc->vc_par[1], vc->vc_par[0]);
+                       return;
+               case 'J':
+                       csi_J(vc, vc->vc_par[0]);
+                       return;
+               case 'K':
+                       csi_K(vc, vc->vc_par[0]);
+                       return;
+               case 'L':
+                       csi_L(vc, vc->vc_par[0]);
+                       return;
+               case 'M':
+                       csi_M(vc, vc->vc_par[0]);
+                       return;
+               case 'P':
+                       csi_P(vc, vc->vc_par[0]);
+                       return;
+               case 'c':
+                       if (!vc->vc_par[0])
+                               respond_ID(tty);
+                       return;
+               case 'g':
+                       if (!vc->vc_par[0])
+                               vc->vc_tab_stop[vc->vc_x >> 5] &= ~(1 << (vc->vc_x & 31));
+                       else if (vc->vc_par[0] == 3) {
+                               vc->vc_tab_stop[0] =
+                                       vc->vc_tab_stop[1] =
+                                       vc->vc_tab_stop[2] =
+                                       vc->vc_tab_stop[3] =
+                                       vc->vc_tab_stop[4] =
+                                       vc->vc_tab_stop[5] =
+                                       vc->vc_tab_stop[6] =
+                                       vc->vc_tab_stop[7] = 0;
+                       }
+                       return;
+               case 'm':
+                       csi_m(vc);
+                       return;
+               case 'q': /* DECLL - but only 3 leds */
+                       /* map 0,1,2,3 to 0,1,2,4 */
+                       if (vc->vc_par[0] < 4)
+                               setledstate(kbd_table + vc->vc_num,
+                                           (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4);
+                       return;
+               case 'r':
+                       if (!vc->vc_par[0])
+                               vc->vc_par[0]++;
+                       if (!vc->vc_par[1])
+                               vc->vc_par[1] = vc->vc_rows;
+                       /* Minimum allowed region is 2 lines */
+                       if (vc->vc_par[0] < vc->vc_par[1] &&
+                           vc->vc_par[1] <= vc->vc_rows) {
+                               vc->vc_top = vc->vc_par[0] - 1;
+                               vc->vc_bottom = vc->vc_par[1];
+                               gotoxay(vc, 0, 0);
+                       }
+                       return;
+               case 's':
+                       save_cur(vc);
+                       return;
+               case 'u':
+                       restore_cur(vc);
+                       return;
+               case 'X':
+                       csi_X(vc, vc->vc_par[0]);
+                       return;
+               case '@':
+                       csi_at(vc, vc->vc_par[0]);
+                       return;
+               case ']': /* setterm functions */
+                       setterm_command(vc);
+                       return;
+               }
+               return;
+       case ESpercent:
+               vc->vc_state = ESnormal;
+               switch (c) {
+               case '@':  /* defined in ISO 2022 */
+                       vc->vc_utf = 0;
+                       return;
+               case 'G':  /* prelim official escape code */
+               case '8':  /* retained for compatibility */
+                       vc->vc_utf = 1;
+                       return;
+               }
+               return;
+       case ESfunckey:
+               vc->vc_state = ESnormal;
+               return;
+       case EShash:
+               vc->vc_state = ESnormal;
+               if (c == '8') {
+                       /* DEC screen alignment test. kludge :-) */
+                       vc->vc_video_erase_char =
+                               (vc->vc_video_erase_char & 0xff00) | 'E';
+                       csi_J(vc, 2);
+                       vc->vc_video_erase_char =
+                               (vc->vc_video_erase_char & 0xff00) | ' ';
+                       do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
+               }
+               return;
+       case ESsetG0:
+               if (c == '0')
+                       vc->vc_G0_charset = GRAF_MAP;
+               else if (c == 'B')
+                       vc->vc_G0_charset = LAT1_MAP;
+               else if (c == 'U')
+                       vc->vc_G0_charset = IBMPC_MAP;
+               else if (c == 'K')
+                       vc->vc_G0_charset = USER_MAP;
+               if (vc->vc_charset == 0)
+                       vc->vc_translate = set_translate(vc->vc_G0_charset, vc);
+               vc->vc_state = ESnormal;
+               return;
+       case ESsetG1:
+               if (c == '0')
+                       vc->vc_G1_charset = GRAF_MAP;
+               else if (c == 'B')
+                       vc->vc_G1_charset = LAT1_MAP;
+               else if (c == 'U')
+                       vc->vc_G1_charset = IBMPC_MAP;
+               else if (c == 'K')
+                       vc->vc_G1_charset = USER_MAP;
+               if (vc->vc_charset == 1)
+                       vc->vc_translate = set_translate(vc->vc_G1_charset, vc);
+               vc->vc_state = ESnormal;
+               return;
+       default:
+               vc->vc_state = ESnormal;
+       }
+}
+
+/* This is a temporary buffer used to prepare a tty console write
+ * so that we can easily avoid touching user space while holding the
+ * console spinlock.  It is allocated in con_init and is shared by
+ * this code and the vc_screen read/write tty calls.
+ *
+ * We have to allocate this statically in the kernel data section
+ * since console_init (and thus con_init) are called before any
+ * kernel memory allocation is available.
+ */
+char con_buf[CON_BUF_SIZE];
+DEFINE_MUTEX(con_buf_mtx);
+
+/* is_double_width() is based on the wcwidth() implementation by
+ * Markus Kuhn -- 2007-05-26 (Unicode 5.0)
+ * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+ */
+struct interval {
+       uint32_t first;
+       uint32_t last;
+};
+
+static int bisearch(uint32_t ucs, const struct interval *table, int max)
+{
+       int min = 0;
+       int mid;
+
+       if (ucs < table[0].first || ucs > table[max].last)
+               return 0;
+       while (max >= min) {
+               mid = (min + max) / 2;
+               if (ucs > table[mid].last)
+                       min = mid + 1;
+               else if (ucs < table[mid].first)
+                       max = mid - 1;
+               else
+                       return 1;
+       }
+       return 0;
+}
+
+static int is_double_width(uint32_t ucs)
+{
+       static const struct interval double_width[] = {
+               { 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E },
+               { 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF },
+               { 0xFE10, 0xFE19 }, { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 },
+               { 0xFFE0, 0xFFE6 }, { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD }
+       };
+       return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1);
+}
+
+/* acquires console_sem */
+static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+#ifdef VT_BUF_VRAM_ONLY
+#define FLUSH do { } while(0);
+#else
+#define FLUSH if (draw_x >= 0) { \
+       vc->vc_sw->con_putcs(vc, (u16 *)draw_from, (u16 *)draw_to - (u16 *)draw_from, vc->vc_y, draw_x); \
+       draw_x = -1; \
+       }
+#endif
+
+       int c, tc, ok, n = 0, draw_x = -1;
+       unsigned int currcons;
+       unsigned long draw_from = 0, draw_to = 0;
+       struct vc_data *vc;
+       unsigned char vc_attr;
+       struct vt_notifier_param param;
+       uint8_t rescan;
+       uint8_t inverse;
+       uint8_t width;
+       u16 himask, charmask;
+
+       if (in_interrupt())
+               return count;
+
+       might_sleep();
+
+       acquire_console_sem();
+       vc = tty->driver_data;
+       if (vc == NULL) {
+               printk(KERN_ERR "vt: argh, driver_data is NULL !\n");
+               release_console_sem();
+               return 0;
+       }
+
+       currcons = vc->vc_num;
+       if (!vc_cons_allocated(currcons)) {
+           /* could this happen? */
+               printk_once("con_write: tty %d not allocated\n", currcons+1);
+           release_console_sem();
+           return 0;
+       }
+
+       himask = vc->vc_hi_font_mask;
+       charmask = himask ? 0x1ff : 0xff;
+
+       /* undraw cursor first */
+       if (IS_FG(vc))
+               hide_cursor(vc);
+
+       param.vc = vc;
+
+       while (!tty->stopped && count) {
+               int orig = *buf;
+               c = orig;
+               buf++;
+               n++;
+               count--;
+               rescan = 0;
+               inverse = 0;
+               width = 1;
+
+               /* Do no translation at all in control states */
+               if (vc->vc_state != ESnormal) {
+                       tc = c;
+               } else if (vc->vc_utf && !vc->vc_disp_ctrl) {
+                   /* Combine UTF-8 into Unicode in vc_utf_char.
+                    * vc_utf_count is the number of continuation bytes still
+                    * expected to arrive.
+                    * vc_npar is the number of continuation bytes arrived so
+                    * far
+                    */
+rescan_last_byte:
+                   if ((c & 0xc0) == 0x80) {
+                       /* Continuation byte received */
+                       static const uint32_t utf8_length_changes[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff };
+                       if (vc->vc_utf_count) {
+                           vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
+                           vc->vc_npar++;
+                           if (--vc->vc_utf_count) {
+                               /* Still need some bytes */
+                               continue;
+                           }
+                           /* Got a whole character */
+                           c = vc->vc_utf_char;
+                           /* Reject overlong sequences */
+                           if (c <= utf8_length_changes[vc->vc_npar - 1] ||
+                                       c > utf8_length_changes[vc->vc_npar])
+                               c = 0xfffd;
+                       } else {
+                           /* Unexpected continuation byte */
+                           vc->vc_utf_count = 0;
+                           c = 0xfffd;
+                       }
+                   } else {
+                       /* Single ASCII byte or first byte of a sequence received */
+                       if (vc->vc_utf_count) {
+                           /* Continuation byte expected */
+                           rescan = 1;
+                           vc->vc_utf_count = 0;
+                           c = 0xfffd;
+                       } else if (c > 0x7f) {
+                           /* First byte of a multibyte sequence received */
+                           vc->vc_npar = 0;
+                           if ((c & 0xe0) == 0xc0) {
+                               vc->vc_utf_count = 1;
+                               vc->vc_utf_char = (c & 0x1f);
+                           } else if ((c & 0xf0) == 0xe0) {
+                               vc->vc_utf_count = 2;
+                               vc->vc_utf_char = (c & 0x0f);
+                           } else if ((c & 0xf8) == 0xf0) {
+                               vc->vc_utf_count = 3;
+                               vc->vc_utf_char = (c & 0x07);
+                           } else if ((c & 0xfc) == 0xf8) {
+                               vc->vc_utf_count = 4;
+                               vc->vc_utf_char = (c & 0x03);
+                           } else if ((c & 0xfe) == 0xfc) {
+                               vc->vc_utf_count = 5;
+                               vc->vc_utf_char = (c & 0x01);
+                           } else {
+                               /* 254 and 255 are invalid */
+                               c = 0xfffd;
+                           }
+                           if (vc->vc_utf_count) {
+                               /* Still need some bytes */
+                               continue;
+                           }
+                       }
+                       /* Nothing to do if an ASCII byte was received */
+                   }
+                   /* End of UTF-8 decoding. */
+                   /* c is the received character, or U+FFFD for invalid sequences. */
+                   /* Replace invalid Unicode code points with U+FFFD too */
+                   if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff)
+                       c = 0xfffd;
+                   tc = c;
+               } else {        /* no utf or alternate charset mode */
+                   tc = vc_translate(vc, c);
+               }
+
+               param.c = tc;
+               if (atomic_notifier_call_chain(&vt_notifier_list, VT_PREWRITE,
+                                       &param) == NOTIFY_STOP)
+                       continue;
+
+                /* If the original code was a control character we
+                 * only allow a glyph to be displayed if the code is
+                 * not normally used (such as for cursor movement) or
+                 * if the disp_ctrl mode has been explicitly enabled.
+                 * Certain characters (as given by the CTRL_ALWAYS
+                 * bitmap) are always displayed as control characters,
+                 * as the console would be pretty useless without
+                 * them; to display an arbitrary font position use the
+                 * direct-to-font zone in UTF-8 mode.
+                 */
+                ok = tc && (c >= 32 ||
+                           !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 :
+                                 vc->vc_utf || ((CTRL_ACTION >> c) & 1)))
+                       && (c != 127 || vc->vc_disp_ctrl)
+                       && (c != 128+27);
+
+               if (vc->vc_state == ESnormal && ok) {
+                       if (vc->vc_utf && !vc->vc_disp_ctrl) {
+                               if (is_double_width(c))
+                                       width = 2;
+                       }
+                       /* Now try to find out how to display it */
+                       tc = conv_uni_to_pc(vc, tc);
+                       if (tc & ~charmask) {
+                               if (tc == -1 || tc == -2) {
+                                   continue; /* nothing to display */
+                               }
+                               /* Glyph not found */
+                               if ((!(vc->vc_utf && !vc->vc_disp_ctrl) || c < 128) && !(c & ~charmask)) {
+                                   /* In legacy mode use the glyph we get by a 1:1 mapping.
+                                      This would make absolutely no sense with Unicode in mind,
+                                      but do this for ASCII characters since a font may lack
+                                      Unicode mapping info and we don't want to end up with
+                                      having question marks only. */
+                                   tc = c;
+                               } else {
+                                   /* Display U+FFFD. If it's not found, display an inverse question mark. */
+                                   tc = conv_uni_to_pc(vc, 0xfffd);
+                                   if (tc < 0) {
+                                       inverse = 1;
+                                       tc = conv_uni_to_pc(vc, '?');
+                                       if (tc < 0) tc = '?';
+                                   }
+                               }
+                       }
+
+                       if (!inverse) {
+                               vc_attr = vc->vc_attr;
+                       } else {
+                               /* invert vc_attr */
+                               if (!vc->vc_can_do_color) {
+                                       vc_attr = (vc->vc_attr) ^ 0x08;
+                               } else if (vc->vc_hi_font_mask == 0x100) {
+                                       vc_attr = ((vc->vc_attr) & 0x11) | (((vc->vc_attr) & 0xe0) >> 4) | (((vc->vc_attr) & 0x0e) << 4);
+                               } else {
+                                       vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4);
+                               }
+                               FLUSH
+                       }
+
+                       while (1) {
+                               if (vc->vc_need_wrap || vc->vc_decim)
+                                       FLUSH
+                               if (vc->vc_need_wrap) {
+                                       cr(vc);
+                                       lf(vc);
+                               }
+                               if (vc->vc_decim)
+                                       insert_char(vc, 1);
+                               scr_writew(himask ?
+                                            ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
+                                            (vc_attr << 8) + tc,
+                                          (u16 *) vc->vc_pos);
+                               if (DO_UPDATE(vc) && draw_x < 0) {
+                                       draw_x = vc->vc_x;
+                                       draw_from = vc->vc_pos;
+                               }
+                               if (vc->vc_x == vc->vc_cols - 1) {
+                                       vc->vc_need_wrap = vc->vc_decawm;
+                                       draw_to = vc->vc_pos + 2;
+                               } else {
+                                       vc->vc_x++;
+                                       draw_to = (vc->vc_pos += 2);
+                               }
+
+                               if (!--width) break;
+
+                               tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */
+                               if (tc < 0) tc = ' ';
+                       }
+                       notify_write(vc, c);
+
+                       if (inverse) {
+                               FLUSH
+                       }
+
+                       if (rescan) {
+                               rescan = 0;
+                               inverse = 0;
+                               width = 1;
+                               c = orig;
+                               goto rescan_last_byte;
+                       }
+                       continue;
+               }
+               FLUSH
+               do_con_trol(tty, vc, orig);
+       }
+       FLUSH
+       console_conditional_schedule();
+       release_console_sem();
+       notify_update(vc);
+       return n;
+#undef FLUSH
+}
+
+/*
+ * This is the console switching callback.
+ *
+ * Doing console switching in a process context allows
+ * us to do the switches asynchronously (needed when we want
+ * to switch due to a keyboard interrupt).  Synchronization
+ * with other console code and prevention of re-entrancy is
+ * ensured with console_sem.
+ */
+static void console_callback(struct work_struct *ignored)
+{
+       acquire_console_sem();
+
+       if (want_console >= 0) {
+               if (want_console != fg_console &&
+                   vc_cons_allocated(want_console)) {
+                       hide_cursor(vc_cons[fg_console].d);
+                       change_console(vc_cons[want_console].d);
+                       /* we only changed when the console had already
+                          been allocated - a new console is not created
+                          in an interrupt routine */
+               }
+               want_console = -1;
+       }
+       if (do_poke_blanked_console) { /* do not unblank for a LED change */
+               do_poke_blanked_console = 0;
+               poke_blanked_console();
+       }
+       if (scrollback_delta) {
+               struct vc_data *vc = vc_cons[fg_console].d;
+               clear_selection();
+               if (vc->vc_mode == KD_TEXT)
+                       vc->vc_sw->con_scrolldelta(vc, scrollback_delta);
+               scrollback_delta = 0;
+       }
+       if (blank_timer_expired) {
+               do_blank_screen(0);
+               blank_timer_expired = 0;
+       }
+       notify_update(vc_cons[fg_console].d);
+
+       release_console_sem();
+}
+
+int set_console(int nr)
+{
+       struct vc_data *vc = vc_cons[fg_console].d;
+
+       if (!vc_cons_allocated(nr) || vt_dont_switch ||
+               (vc->vt_mode.mode == VT_AUTO && vc->vc_mode == KD_GRAPHICS)) {
+
+               /*
+                * Console switch will fail in console_callback() or
+                * change_console() so there is no point scheduling
+                * the callback
+                *
+                * Existing set_console() users don't check the return
+                * value so this shouldn't break anything
+                */
+               return -EINVAL;
+       }
+
+       want_console = nr;
+       schedule_console_callback();
+
+       return 0;
+}
+
+struct tty_driver *console_driver;
+
+#ifdef CONFIG_VT_CONSOLE
+
+/**
+ * vt_kmsg_redirect() - Sets/gets the kernel message console
+ * @new:       The new virtual terminal number or -1 if the console should stay
+ *             unchanged
+ *
+ * By default, the kernel messages are always printed on the current virtual
+ * console. However, the user may modify that default with the
+ * TIOCL_SETKMSGREDIRECT ioctl call.
+ *
+ * This function sets the kernel message console to be @new. It returns the old
+ * virtual console number. The virtual terminal number 0 (both as parameter and
+ * return value) means no redirection (i.e. always printed on the currently
+ * active console).
+ *
+ * The parameter -1 means that only the current console is returned, but the
+ * value is not modified. You may use the macro vt_get_kmsg_redirect() in that
+ * case to make the code more understandable.
+ *
+ * When the kernel is compiled without CONFIG_VT_CONSOLE, this function ignores
+ * the parameter and always returns 0.
+ */
+int vt_kmsg_redirect(int new)
+{
+       static int kmsg_con;
+
+       if (new != -1)
+               return xchg(&kmsg_con, new);
+       else
+               return kmsg_con;
+}
+
+/*
+ *     Console on virtual terminal
+ *
+ * The console must be locked when we get here.
+ */
+
+static void vt_console_print(struct console *co, const char *b, unsigned count)
+{
+       struct vc_data *vc = vc_cons[fg_console].d;
+       unsigned char c;
+       static DEFINE_SPINLOCK(printing_lock);
+       const ushort *start;
+       ushort cnt = 0;
+       ushort myx;
+       int kmsg_console;
+
+       /* console busy or not yet initialized */
+       if (!printable)
+               return;
+       if (!spin_trylock(&printing_lock))
+               return;
+
+       kmsg_console = vt_get_kmsg_redirect();
+       if (kmsg_console && vc_cons_allocated(kmsg_console - 1))
+               vc = vc_cons[kmsg_console - 1].d;
+
+       /* read `x' only after setting currcons properly (otherwise
+          the `x' macro will read the x of the foreground console). */
+       myx = vc->vc_x;
+
+       if (!vc_cons_allocated(fg_console)) {
+               /* impossible */
+               /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */
+               goto quit;
+       }
+
+       if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc))
+               goto quit;
+
+       /* undraw cursor first */
+       if (IS_FG(vc))
+               hide_cursor(vc);
+
+       start = (ushort *)vc->vc_pos;
+
+       /* Contrived structure to try to emulate original need_wrap behaviour
+        * Problems caused when we have need_wrap set on '\n' character */
+       while (count--) {
+               c = *b++;
+               if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
+                       if (cnt > 0) {
+                               if (CON_IS_VISIBLE(vc))
+                                       vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
+                               vc->vc_x += cnt;
+                               if (vc->vc_need_wrap)
+                                       vc->vc_x--;
+                               cnt = 0;
+                       }
+                       if (c == 8) {           /* backspace */
+                               bs(vc);
+                               start = (ushort *)vc->vc_pos;
+                               myx = vc->vc_x;
+                               continue;
+                       }
+                       if (c != 13)
+                               lf(vc);
+                       cr(vc);
+                       start = (ushort *)vc->vc_pos;
+                       myx = vc->vc_x;
+                       if (c == 10 || c == 13)
+                               continue;
+               }
+               scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos);
+               notify_write(vc, c);
+               cnt++;
+               if (myx == vc->vc_cols - 1) {
+                       vc->vc_need_wrap = 1;
+                       continue;
+               }
+               vc->vc_pos += 2;
+               myx++;
+       }
+       if (cnt > 0) {
+               if (CON_IS_VISIBLE(vc))
+                       vc->vc_sw->con_putcs(vc, start, cnt, vc->vc_y, vc->vc_x);
+               vc->vc_x += cnt;
+               if (vc->vc_x == vc->vc_cols) {
+                       vc->vc_x--;
+                       vc->vc_need_wrap = 1;
+               }
+       }
+       set_cursor(vc);
+       notify_update(vc);
+
+quit:
+       spin_unlock(&printing_lock);
+}
+
+static struct tty_driver *vt_console_device(struct console *c, int *index)
+{
+       *index = c->index ? c->index-1 : fg_console;
+       return console_driver;
+}
+
+static struct console vt_console_driver = {
+       .name           = "tty",
+       .write          = vt_console_print,
+       .device         = vt_console_device,
+       .unblank        = unblank_screen,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+};
+#endif
+
+/*
+ *     Handling of Linux-specific VC ioctls
+ */
+
+/*
+ * Generally a bit racy with respect to console_sem().
+ *
+ * There are some functions which don't need it.
+ *
+ * There are some functions which can sleep for arbitrary periods
+ * (paste_selection) but we don't need the lock there anyway.
+ *
+ * set_selection has locking, and definitely needs it
+ */
+
+int tioclinux(struct tty_struct *tty, unsigned long arg)
+{
+       char type, data;
+       char __user *p = (char __user *)arg;
+       int lines;
+       int ret;
+
+       if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       if (get_user(type, p))
+               return -EFAULT;
+       ret = 0;
+
+       switch (type)
+       {
+               case TIOCL_SETSEL:
+                       acquire_console_sem();
+                       ret = set_selection((struct tiocl_selection __user *)(p+1), tty);
+                       release_console_sem();
+                       break;
+               case TIOCL_PASTESEL:
+                       ret = paste_selection(tty);
+                       break;
+               case TIOCL_UNBLANKSCREEN:
+                       acquire_console_sem();
+                       unblank_screen();
+                       release_console_sem();
+                       break;
+               case TIOCL_SELLOADLUT:
+                       ret = sel_loadlut(p);
+                       break;
+               case TIOCL_GETSHIFTSTATE:
+
+       /*
+        * Make it possible to react to Shift+Mousebutton.
+        * Note that 'shift_state' is an undocumented
+        * kernel-internal variable; programs not closely
+        * related to the kernel should not use this.
+        */
+                       data = shift_state;
+                       ret = __put_user(data, p);
+                       break;
+               case TIOCL_GETMOUSEREPORTING:
+                       data = mouse_reporting();
+                       ret = __put_user(data, p);
+                       break;
+               case TIOCL_SETVESABLANK:
+                       ret = set_vesa_blanking(p);
+                       break;
+               case TIOCL_GETKMSGREDIRECT:
+                       data = vt_get_kmsg_redirect();
+                       ret = __put_user(data, p);
+                       break;
+               case TIOCL_SETKMSGREDIRECT:
+                       if (!capable(CAP_SYS_ADMIN)) {
+                               ret = -EPERM;
+                       } else {
+                               if (get_user(data, p+1))
+                                       ret = -EFAULT;
+                               else
+                                       vt_kmsg_redirect(data);
+                       }
+                       break;
+               case TIOCL_GETFGCONSOLE:
+                       ret = fg_console;
+                       break;
+               case TIOCL_SCROLLCONSOLE:
+                       if (get_user(lines, (s32 __user *)(p+4))) {
+                               ret = -EFAULT;
+                       } else {
+                               scrollfront(vc_cons[fg_console].d, lines);
+                               ret = 0;
+                       }
+                       break;
+               case TIOCL_BLANKSCREEN: /* until explicitly unblanked, not only poked */
+                       acquire_console_sem();
+                       ignore_poke = 1;
+                       do_blank_screen(0);
+                       release_console_sem();
+                       break;
+               case TIOCL_BLANKEDSCREEN:
+                       ret = console_blanked;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       break;
+       }
+       return ret;
+}
+
+/*
+ * /dev/ttyN handling
+ */
+
+static int con_write(struct tty_struct *tty, const unsigned char *buf, int count)
+{
+       int     retval;
+
+       retval = do_con_write(tty, buf, count);
+       con_flush_chars(tty);
+
+       return retval;
+}
+
+static int con_put_char(struct tty_struct *tty, unsigned char ch)
+{
+       if (in_interrupt())
+               return 0;       /* n_r3964 calls put_char() from interrupt context */
+       return do_con_write(tty, &ch, 1);
+}
+
+static int con_write_room(struct tty_struct *tty)
+{
+       if (tty->stopped)
+               return 0;
+       return 32768;           /* No limit, really; we're not buffering */
+}
+
+static int con_chars_in_buffer(struct tty_struct *tty)
+{
+       return 0;               /* we're not buffering */
+}
+
+/*
+ * con_throttle and con_unthrottle are only used for
+ * paste_selection(), which has to stuff in a large number of
+ * characters...
+ */
+static void con_throttle(struct tty_struct *tty)
+{
+}
+
+static void con_unthrottle(struct tty_struct *tty)
+{
+       struct vc_data *vc = tty->driver_data;
+
+       wake_up_interruptible(&vc->paste_wait);
+}
+
+/*
+ * Turn the Scroll-Lock LED on when the tty is stopped
+ */
+static void con_stop(struct tty_struct *tty)
+{
+       int console_num;
+       if (!tty)
+               return;
+       console_num = tty->index;
+       if (!vc_cons_allocated(console_num))
+               return;
+       set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
+       set_leds();
+}
+
+/*
+ * Turn the Scroll-Lock LED off when the console is started
+ */
+static void con_start(struct tty_struct *tty)
+{
+       int console_num;
+       if (!tty)
+               return;
+       console_num = tty->index;
+       if (!vc_cons_allocated(console_num))
+               return;
+       clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
+       set_leds();
+}
+
+static void con_flush_chars(struct tty_struct *tty)
+{
+       struct vc_data *vc;
+
+       if (in_interrupt())     /* from flush_to_ldisc */
+               return;
+
+       /* if we race with con_close(), vt may be null */
+       acquire_console_sem();
+       vc = tty->driver_data;
+       if (vc)
+               set_cursor(vc);
+       release_console_sem();
+}
+
+/*
+ * Allocate the console screen memory.
+ */
+static int con_open(struct tty_struct *tty, struct file *filp)
+{
+       unsigned int currcons = tty->index;
+       int ret = 0;
+
+       acquire_console_sem();
+       if (tty->driver_data == NULL) {
+               ret = vc_allocate(currcons);
+               if (ret == 0) {
+                       struct vc_data *vc = vc_cons[currcons].d;
+
+                       /* Still being freed */
+                       if (vc->port.tty) {
+                               release_console_sem();
+                               return -ERESTARTSYS;
+                       }
+                       tty->driver_data = vc;
+                       vc->port.tty = tty;
+
+                       if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
+                               tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
+                               tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
+                       }
+                       if (vc->vc_utf)
+                               tty->termios->c_iflag |= IUTF8;
+                       else
+                               tty->termios->c_iflag &= ~IUTF8;
+                       release_console_sem();
+                       return ret;
+               }
+       }
+       release_console_sem();
+       return ret;
+}
+
+static void con_close(struct tty_struct *tty, struct file *filp)
+{
+       /* Nothing to do - we defer to shutdown */
+}
+
+static void con_shutdown(struct tty_struct *tty)
+{
+       struct vc_data *vc = tty->driver_data;
+       BUG_ON(vc == NULL);
+       acquire_console_sem();
+       vc->port.tty = NULL;
+       release_console_sem();
+       tty_shutdown(tty);
+}
+
+static int default_italic_color    = 2; // green (ASCII)
+static int default_underline_color = 3; // cyan (ASCII)
+module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR);
+module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR);
+
+static void vc_init(struct vc_data *vc, unsigned int rows,
+                   unsigned int cols, int do_clear)
+{
+       int j, k ;
+
+       vc->vc_cols = cols;
+       vc->vc_rows = rows;
+       vc->vc_size_row = cols << 1;
+       vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
+
+       set_origin(vc);
+       vc->vc_pos = vc->vc_origin;
+       reset_vc(vc);
+       for (j=k=0; j<16; j++) {
+               vc->vc_palette[k++] = default_red[j] ;
+               vc->vc_palette[k++] = default_grn[j] ;
+               vc->vc_palette[k++] = default_blu[j] ;
+       }
+       vc->vc_def_color       = 0x07;   /* white */
+       vc->vc_ulcolor         = default_underline_color;
+       vc->vc_itcolor         = default_italic_color;
+       vc->vc_halfcolor       = 0x08;   /* grey */
+       init_waitqueue_head(&vc->paste_wait);
+       reset_terminal(vc, do_clear);
+}
+
+/*
+ * This routine initializes console interrupts, and does nothing
+ * else. If you want the screen to clear, call tty_write with
+ * the appropriate escape-sequence.
+ */
+
+static int __init con_init(void)
+{
+       const char *display_desc = NULL;
+       struct vc_data *vc;
+       unsigned int currcons = 0, i;
+
+       acquire_console_sem();
+
+       if (conswitchp)
+               display_desc = conswitchp->con_startup();
+       if (!display_desc) {
+               fg_console = 0;
+               release_console_sem();
+               return 0;
+       }
+
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               struct con_driver *con_driver = &registered_con_driver[i];
+
+               if (con_driver->con == NULL) {
+                       con_driver->con = conswitchp;
+                       con_driver->desc = display_desc;
+                       con_driver->flag = CON_DRIVER_FLAG_INIT;
+                       con_driver->first = 0;
+                       con_driver->last = MAX_NR_CONSOLES - 1;
+                       break;
+               }
+       }
+
+       for (i = 0; i < MAX_NR_CONSOLES; i++)
+               con_driver_map[i] = conswitchp;
+
+       if (blankinterval) {
+               blank_state = blank_normal_wait;
+               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
+       }
+
+       for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
+               vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
+               INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
+               tty_port_init(&vc->port);
+               visual_init(vc, currcons, 1);
+               vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
+               vc_init(vc, vc->vc_rows, vc->vc_cols,
+                       currcons || !vc->vc_sw->con_save_screen);
+       }
+       currcons = fg_console = 0;
+       master_display_fg = vc = vc_cons[currcons].d;
+       set_origin(vc);
+       save_screen(vc);
+       gotoxy(vc, vc->vc_x, vc->vc_y);
+       csi_J(vc, 0);
+       update_screen(vc);
+       printk("Console: %s %s %dx%d",
+               vc->vc_can_do_color ? "colour" : "mono",
+               display_desc, vc->vc_cols, vc->vc_rows);
+       printable = 1;
+       printk("\n");
+
+       release_console_sem();
+
+#ifdef CONFIG_VT_CONSOLE
+       register_console(&vt_console_driver);
+#endif
+       return 0;
+}
+console_initcall(con_init);
+
+static const struct tty_operations con_ops = {
+       .open = con_open,
+       .close = con_close,
+       .write = con_write,
+       .write_room = con_write_room,
+       .put_char = con_put_char,
+       .flush_chars = con_flush_chars,
+       .chars_in_buffer = con_chars_in_buffer,
+       .ioctl = vt_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = vt_compat_ioctl,
+#endif
+       .stop = con_stop,
+       .start = con_start,
+       .throttle = con_throttle,
+       .unthrottle = con_unthrottle,
+       .resize = vt_resize,
+       .shutdown = con_shutdown
+};
+
+static struct cdev vc0_cdev;
+
+int __init vty_init(const struct file_operations *console_fops)
+{
+       cdev_init(&vc0_cdev, console_fops);
+       if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
+           register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
+               panic("Couldn't register /dev/tty0 driver\n");
+       device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
+
+       vcs_init();
+
+       console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
+       if (!console_driver)
+               panic("Couldn't allocate console driver\n");
+       console_driver->owner = THIS_MODULE;
+       console_driver->name = "tty";
+       console_driver->name_base = 1;
+       console_driver->major = TTY_MAJOR;
+       console_driver->minor_start = 1;
+       console_driver->type = TTY_DRIVER_TYPE_CONSOLE;
+       console_driver->init_termios = tty_std_termios;
+       if (default_utf8)
+               console_driver->init_termios.c_iflag |= IUTF8;
+       console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
+       tty_set_operations(console_driver, &con_ops);
+       if (tty_register_driver(console_driver))
+               panic("Couldn't register console driver\n");
+       kbd_init();
+       console_map_init();
+#ifdef CONFIG_MDA_CONSOLE
+       mda_console_init();
+#endif
+       return 0;
+}
+
+#ifndef VT_SINGLE_DRIVER
+
+static struct class *vtconsole_class;
+
+static int bind_con_driver(const struct consw *csw, int first, int last,
+                          int deflt)
+{
+       struct module *owner = csw->owner;
+       const char *desc = NULL;
+       struct con_driver *con_driver;
+       int i, j = -1, k = -1, retval = -ENODEV;
+
+       if (!try_module_get(owner))
+               return -ENODEV;
+
+       acquire_console_sem();
+
+       /* check if driver is registered */
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               con_driver = &registered_con_driver[i];
+
+               if (con_driver->con == csw) {
+                       desc = con_driver->desc;
+                       retval = 0;
+                       break;
+               }
+       }
+
+       if (retval)
+               goto err;
+
+       if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) {
+               csw->con_startup();
+               con_driver->flag |= CON_DRIVER_FLAG_INIT;
+       }
+
+       if (deflt) {
+               if (conswitchp)
+                       module_put(conswitchp->owner);
+
+               __module_get(owner);
+               conswitchp = csw;
+       }
+
+       first = max(first, con_driver->first);
+       last = min(last, con_driver->last);
+
+       for (i = first; i <= last; i++) {
+               int old_was_color;
+               struct vc_data *vc = vc_cons[i].d;
+
+               if (con_driver_map[i])
+                       module_put(con_driver_map[i]->owner);
+               __module_get(owner);
+               con_driver_map[i] = csw;
+
+               if (!vc || !vc->vc_sw)
+                       continue;
+
+               j = i;
+
+               if (CON_IS_VISIBLE(vc)) {
+                       k = i;
+                       save_screen(vc);
+               }
+
+               old_was_color = vc->vc_can_do_color;
+               vc->vc_sw->con_deinit(vc);
+               vc->vc_origin = (unsigned long)vc->vc_screenbuf;
+               visual_init(vc, i, 0);
+               set_origin(vc);
+               update_attr(vc);
+
+               /* If the console changed between mono <-> color, then
+                * the attributes in the screenbuf will be wrong.  The
+                * following resets all attributes to something sane.
+                */
+               if (old_was_color != vc->vc_can_do_color)
+                       clear_buffer_attributes(vc);
+       }
+
+       printk("Console: switching ");
+       if (!deflt)
+               printk("consoles %d-%d ", first+1, last+1);
+       if (j >= 0) {
+               struct vc_data *vc = vc_cons[j].d;
+
+               printk("to %s %s %dx%d\n",
+                      vc->vc_can_do_color ? "colour" : "mono",
+                      desc, vc->vc_cols, vc->vc_rows);
+
+               if (k >= 0) {
+                       vc = vc_cons[k].d;
+                       update_screen(vc);
+               }
+       } else
+               printk("to %s\n", desc);
+
+       retval = 0;
+err:
+       release_console_sem();
+       module_put(owner);
+       return retval;
+};
+
+#ifdef CONFIG_VT_HW_CONSOLE_BINDING
+static int con_is_graphics(const struct consw *csw, int first, int last)
+{
+       int i, retval = 0;
+
+       for (i = first; i <= last; i++) {
+               struct vc_data *vc = vc_cons[i].d;
+
+               if (vc && vc->vc_mode == KD_GRAPHICS) {
+                       retval = 1;
+                       break;
+               }
+       }
+
+       return retval;
+}
+
+/**
+ * unbind_con_driver - unbind a console driver
+ * @csw: pointer to console driver to unregister
+ * @first: first in range of consoles that @csw should be unbound from
+ * @last: last in range of consoles that @csw should be unbound from
+ * @deflt: should next bound console driver be default after @csw is unbound?
+ *
+ * To unbind a driver from all possible consoles, pass 0 as @first and
+ * %MAX_NR_CONSOLES as @last.
+ *
+ * @deflt controls whether the console that ends up replacing @csw should be
+ * the default console.
+ *
+ * RETURNS:
+ * -ENODEV if @csw isn't a registered console driver or can't be unregistered
+ * or 0 on success.
+ */
+int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
+{
+       struct module *owner = csw->owner;
+       const struct consw *defcsw = NULL;
+       struct con_driver *con_driver = NULL, *con_back = NULL;
+       int i, retval = -ENODEV;
+
+       if (!try_module_get(owner))
+               return -ENODEV;
+
+       acquire_console_sem();
+
+       /* check if driver is registered and if it is unbindable */
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               con_driver = &registered_con_driver[i];
+
+               if (con_driver->con == csw &&
+                   con_driver->flag & CON_DRIVER_FLAG_MODULE) {
+                       retval = 0;
+                       break;
+               }
+       }
+
+       if (retval) {
+               release_console_sem();
+               goto err;
+       }
+
+       retval = -ENODEV;
+
+       /* check if backup driver exists */
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               con_back = &registered_con_driver[i];
+
+               if (con_back->con &&
+                   !(con_back->flag & CON_DRIVER_FLAG_MODULE)) {
+                       defcsw = con_back->con;
+                       retval = 0;
+                       break;
+               }
+       }
+
+       if (retval) {
+               release_console_sem();
+               goto err;
+       }
+
+       if (!con_is_bound(csw)) {
+               release_console_sem();
+               goto err;
+       }
+
+       first = max(first, con_driver->first);
+       last = min(last, con_driver->last);
+
+       for (i = first; i <= last; i++) {
+               if (con_driver_map[i] == csw) {
+                       module_put(csw->owner);
+                       con_driver_map[i] = NULL;
+               }
+       }
+
+       if (!con_is_bound(defcsw)) {
+               const struct consw *defconsw = conswitchp;
+
+               defcsw->con_startup();
+               con_back->flag |= CON_DRIVER_FLAG_INIT;
+               /*
+                * vgacon may change the default driver to point
+                * to dummycon, we restore it here...
+                */
+               conswitchp = defconsw;
+       }
+
+       if (!con_is_bound(csw))
+               con_driver->flag &= ~CON_DRIVER_FLAG_INIT;
+
+       release_console_sem();
+       /* ignore return value, binding should not fail */
+       bind_con_driver(defcsw, first, last, deflt);
+err:
+       module_put(owner);
+       return retval;
+
+}
+EXPORT_SYMBOL(unbind_con_driver);
+
+static int vt_bind(struct con_driver *con)
+{
+       const struct consw *defcsw = NULL, *csw = NULL;
+       int i, more = 1, first = -1, last = -1, deflt = 0;
+
+       if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
+           con_is_graphics(con->con, con->first, con->last))
+               goto err;
+
+       csw = con->con;
+
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               struct con_driver *con = &registered_con_driver[i];
+
+               if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) {
+                       defcsw = con->con;
+                       break;
+               }
+       }
+
+       if (!defcsw)
+               goto err;
+
+       while (more) {
+               more = 0;
+
+               for (i = con->first; i <= con->last; i++) {
+                       if (con_driver_map[i] == defcsw) {
+                               if (first == -1)
+                                       first = i;
+                               last = i;
+                               more = 1;
+                       } else if (first != -1)
+                               break;
+               }
+
+               if (first == 0 && last == MAX_NR_CONSOLES -1)
+                       deflt = 1;
+
+               if (first != -1)
+                       bind_con_driver(csw, first, last, deflt);
+
+               first = -1;
+               last = -1;
+               deflt = 0;
+       }
+
+err:
+       return 0;
+}
+
+static int vt_unbind(struct con_driver *con)
+{
+       const struct consw *csw = NULL;
+       int i, more = 1, first = -1, last = -1, deflt = 0;
+
+       if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
+           con_is_graphics(con->con, con->first, con->last))
+               goto err;
+
+       csw = con->con;
+
+       while (more) {
+               more = 0;
+
+               for (i = con->first; i <= con->last; i++) {
+                       if (con_driver_map[i] == csw) {
+                               if (first == -1)
+                                       first = i;
+                               last = i;
+                               more = 1;
+                       } else if (first != -1)
+                               break;
+               }
+
+               if (first == 0 && last == MAX_NR_CONSOLES -1)
+                       deflt = 1;
+
+               if (first != -1)
+                       unbind_con_driver(csw, first, last, deflt);
+
+               first = -1;
+               last = -1;
+               deflt = 0;
+       }
+
+err:
+       return 0;
+}
+#else
+static inline int vt_bind(struct con_driver *con)
+{
+       return 0;
+}
+static inline int vt_unbind(struct con_driver *con)
+{
+       return 0;
+}
+#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
+
+static ssize_t store_bind(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       struct con_driver *con = dev_get_drvdata(dev);
+       int bind = simple_strtoul(buf, NULL, 0);
+
+       if (bind)
+               vt_bind(con);
+       else
+               vt_unbind(con);
+
+       return count;
+}
+
+static ssize_t show_bind(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct con_driver *con = dev_get_drvdata(dev);
+       int bind = con_is_bound(con->con);
+
+       return snprintf(buf, PAGE_SIZE, "%i\n", bind);
+}
+
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+                        char *buf)
+{
+       struct con_driver *con = dev_get_drvdata(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%s %s\n",
+                       (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)",
+                        con->desc);
+
+}
+
+static struct device_attribute device_attrs[] = {
+       __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind),
+       __ATTR(name, S_IRUGO, show_name, NULL),
+};
+
+static int vtconsole_init_device(struct con_driver *con)
+{
+       int i;
+       int error = 0;
+
+       con->flag |= CON_DRIVER_FLAG_ATTR;
+       dev_set_drvdata(con->dev, con);
+       for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
+               error = device_create_file(con->dev, &device_attrs[i]);
+               if (error)
+                       break;
+       }
+
+       if (error) {
+               while (--i >= 0)
+                       device_remove_file(con->dev, &device_attrs[i]);
+               con->flag &= ~CON_DRIVER_FLAG_ATTR;
+       }
+
+       return error;
+}
+
+static void vtconsole_deinit_device(struct con_driver *con)
+{
+       int i;
+
+       if (con->flag & CON_DRIVER_FLAG_ATTR) {
+               for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
+                       device_remove_file(con->dev, &device_attrs[i]);
+               con->flag &= ~CON_DRIVER_FLAG_ATTR;
+       }
+}
+
+/**
+ * con_is_bound - checks if driver is bound to the console
+ * @csw: console driver
+ *
+ * RETURNS: zero if unbound, nonzero if bound
+ *
+ * Drivers can call this and if zero, they should release
+ * all resources allocated on con_startup()
+ */
+int con_is_bound(const struct consw *csw)
+{
+       int i, bound = 0;
+
+       for (i = 0; i < MAX_NR_CONSOLES; i++) {
+               if (con_driver_map[i] == csw) {
+                       bound = 1;
+                       break;
+               }
+       }
+
+       return bound;
+}
+EXPORT_SYMBOL(con_is_bound);
+
+/**
+ * con_debug_enter - prepare the console for the kernel debugger
+ * @sw: console driver
+ *
+ * Called when the console is taken over by the kernel debugger, this
+ * function needs to save the current console state, then put the console
+ * into a state suitable for the kernel debugger.
+ *
+ * RETURNS:
+ * Zero on success, nonzero if a failure occurred when trying to prepare
+ * the console for the debugger.
+ */
+int con_debug_enter(struct vc_data *vc)
+{
+       int ret = 0;
+
+       saved_fg_console = fg_console;
+       saved_last_console = last_console;
+       saved_want_console = want_console;
+       saved_vc_mode = vc->vc_mode;
+       saved_console_blanked = console_blanked;
+       vc->vc_mode = KD_TEXT;
+       console_blanked = 0;
+       if (vc->vc_sw->con_debug_enter)
+               ret = vc->vc_sw->con_debug_enter(vc);
+#ifdef CONFIG_KGDB_KDB
+       /* Set the initial LINES variable if it is not already set */
+       if (vc->vc_rows < 999) {
+               int linecount;
+               char lns[4];
+               const char *setargs[3] = {
+                       "set",
+                       "LINES",
+                       lns,
+               };
+               if (kdbgetintenv(setargs[0], &linecount)) {
+                       snprintf(lns, 4, "%i", vc->vc_rows);
+                       kdb_set(2, setargs);
+               }
+       }
+#endif /* CONFIG_KGDB_KDB */
+       return ret;
+}
+EXPORT_SYMBOL_GPL(con_debug_enter);
+
+/**
+ * con_debug_leave - restore console state
+ * @sw: console driver
+ *
+ * Restore the console state to what it was before the kernel debugger
+ * was invoked.
+ *
+ * RETURNS:
+ * Zero on success, nonzero if a failure occurred when trying to restore
+ * the console.
+ */
+int con_debug_leave(void)
+{
+       struct vc_data *vc;
+       int ret = 0;
+
+       fg_console = saved_fg_console;
+       last_console = saved_last_console;
+       want_console = saved_want_console;
+       console_blanked = saved_console_blanked;
+       vc_cons[fg_console].d->vc_mode = saved_vc_mode;
+
+       vc = vc_cons[fg_console].d;
+       if (vc->vc_sw->con_debug_leave)
+               ret = vc->vc_sw->con_debug_leave(vc);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(con_debug_leave);
+
+/**
+ * register_con_driver - register console driver to console layer
+ * @csw: console driver
+ * @first: the first console to take over, minimum value is 0
+ * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1
+ *
+ * DESCRIPTION: This function registers a console driver which can later
+ * bind to a range of consoles specified by @first and @last. It will
+ * also initialize the console driver by calling con_startup().
+ */
+int register_con_driver(const struct consw *csw, int first, int last)
+{
+       struct module *owner = csw->owner;
+       struct con_driver *con_driver;
+       const char *desc;
+       int i, retval = 0;
+
+       if (!try_module_get(owner))
+               return -ENODEV;
+
+       acquire_console_sem();
+
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               con_driver = &registered_con_driver[i];
+
+               /* already registered */
+               if (con_driver->con == csw)
+                       retval = -EINVAL;
+       }
+
+       if (retval)
+               goto err;
+
+       desc = csw->con_startup();
+
+       if (!desc)
+               goto err;
+
+       retval = -EINVAL;
+
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               con_driver = &registered_con_driver[i];
+
+               if (con_driver->con == NULL) {
+                       con_driver->con = csw;
+                       con_driver->desc = desc;
+                       con_driver->node = i;
+                       con_driver->flag = CON_DRIVER_FLAG_MODULE |
+                                          CON_DRIVER_FLAG_INIT;
+                       con_driver->first = first;
+                       con_driver->last = last;
+                       retval = 0;
+                       break;
+               }
+       }
+
+       if (retval)
+               goto err;
+
+       con_driver->dev = device_create(vtconsole_class, NULL,
+                                               MKDEV(0, con_driver->node),
+                                               NULL, "vtcon%i",
+                                               con_driver->node);
+
+       if (IS_ERR(con_driver->dev)) {
+               printk(KERN_WARNING "Unable to create device for %s; "
+                      "errno = %ld\n", con_driver->desc,
+                      PTR_ERR(con_driver->dev));
+               con_driver->dev = NULL;
+       } else {
+               vtconsole_init_device(con_driver);
+       }
+
+err:
+       release_console_sem();
+       module_put(owner);
+       return retval;
+}
+EXPORT_SYMBOL(register_con_driver);
+
+/**
+ * unregister_con_driver - unregister console driver from console layer
+ * @csw: console driver
+ *
+ * DESCRIPTION: All drivers that registers to the console layer must
+ * call this function upon exit, or if the console driver is in a state
+ * where it won't be able to handle console services, such as the
+ * framebuffer console without loaded framebuffer drivers.
+ *
+ * The driver must unbind first prior to unregistration.
+ */
+int unregister_con_driver(const struct consw *csw)
+{
+       int i, retval = -ENODEV;
+
+       acquire_console_sem();
+
+       /* cannot unregister a bound driver */
+       if (con_is_bound(csw))
+               goto err;
+
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               struct con_driver *con_driver = &registered_con_driver[i];
+
+               if (con_driver->con == csw &&
+                   con_driver->flag & CON_DRIVER_FLAG_MODULE) {
+                       vtconsole_deinit_device(con_driver);
+                       device_destroy(vtconsole_class,
+                                      MKDEV(0, con_driver->node));
+                       con_driver->con = NULL;
+                       con_driver->desc = NULL;
+                       con_driver->dev = NULL;
+                       con_driver->node = 0;
+                       con_driver->flag = 0;
+                       con_driver->first = 0;
+                       con_driver->last = 0;
+                       retval = 0;
+                       break;
+               }
+       }
+err:
+       release_console_sem();
+       return retval;
+}
+EXPORT_SYMBOL(unregister_con_driver);
+
+/*
+ *     If we support more console drivers, this function is used
+ *     when a driver wants to take over some existing consoles
+ *     and become default driver for newly opened ones.
+ *
+ *      take_over_console is basically a register followed by unbind
+ */
+int take_over_console(const struct consw *csw, int first, int last, int deflt)
+{
+       int err;
+
+       err = register_con_driver(csw, first, last);
+
+       if (!err)
+               bind_con_driver(csw, first, last, deflt);
+
+       return err;
+}
+
+/*
+ * give_up_console is a wrapper to unregister_con_driver. It will only
+ * work if driver is fully unbound.
+ */
+void give_up_console(const struct consw *csw)
+{
+       unregister_con_driver(csw);
+}
+
+static int __init vtconsole_class_init(void)
+{
+       int i;
+
+       vtconsole_class = class_create(THIS_MODULE, "vtconsole");
+       if (IS_ERR(vtconsole_class)) {
+               printk(KERN_WARNING "Unable to create vt console class; "
+                      "errno = %ld\n", PTR_ERR(vtconsole_class));
+               vtconsole_class = NULL;
+       }
+
+       /* Add system drivers to sysfs */
+       for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+               struct con_driver *con = &registered_con_driver[i];
+
+               if (con->con && !con->dev) {
+                       con->dev = device_create(vtconsole_class, NULL,
+                                                        MKDEV(0, con->node),
+                                                        NULL, "vtcon%i",
+                                                        con->node);
+
+                       if (IS_ERR(con->dev)) {
+                               printk(KERN_WARNING "Unable to create "
+                                      "device for %s; errno = %ld\n",
+                                      con->desc, PTR_ERR(con->dev));
+                               con->dev = NULL;
+                       } else {
+                               vtconsole_init_device(con);
+                       }
+               }
+       }
+
+       return 0;
+}
+postcore_initcall(vtconsole_class_init);
+
+#endif
+
+/*
+ *     Screen blanking
+ */
+
+static int set_vesa_blanking(char __user *p)
+{
+       unsigned int mode;
+
+       if (get_user(mode, p + 1))
+               return -EFAULT;
+
+       vesa_blank_mode = (mode < 4) ? mode : 0;
+       return 0;
+}
+
+void do_blank_screen(int entering_gfx)
+{
+       struct vc_data *vc = vc_cons[fg_console].d;
+       int i;
+
+       WARN_CONSOLE_UNLOCKED();
+
+       if (console_blanked) {
+               if (blank_state == blank_vesa_wait) {
+                       blank_state = blank_off;
+                       vc->vc_sw->con_blank(vc, vesa_blank_mode + 1, 0);
+               }
+               return;
+       }
+
+       /* entering graphics mode? */
+       if (entering_gfx) {
+               hide_cursor(vc);
+               save_screen(vc);
+               vc->vc_sw->con_blank(vc, -1, 1);
+               console_blanked = fg_console + 1;
+               blank_state = blank_off;
+               set_origin(vc);
+               return;
+       }
+
+       if (blank_state != blank_normal_wait)
+               return;
+       blank_state = blank_off;
+
+       /* don't blank graphics */
+       if (vc->vc_mode != KD_TEXT) {
+               console_blanked = fg_console + 1;
+               return;
+       }
+
+       hide_cursor(vc);
+       del_timer_sync(&console_timer);
+       blank_timer_expired = 0;
+
+       save_screen(vc);
+       /* In case we need to reset origin, blanking hook returns 1 */
+       i = vc->vc_sw->con_blank(vc, vesa_off_interval ? 1 : (vesa_blank_mode + 1), 0);
+       console_blanked = fg_console + 1;
+       if (i)
+               set_origin(vc);
+
+       if (console_blank_hook && console_blank_hook(1))
+               return;
+
+       if (vesa_off_interval && vesa_blank_mode) {
+               blank_state = blank_vesa_wait;
+               mod_timer(&console_timer, jiffies + vesa_off_interval);
+       }
+       vt_event_post(VT_EVENT_BLANK, vc->vc_num, vc->vc_num);
+}
+EXPORT_SYMBOL(do_blank_screen);
+
+/*
+ * Called by timer as well as from vt_console_driver
+ */
+void do_unblank_screen(int leaving_gfx)
+{
+       struct vc_data *vc;
+
+       /* This should now always be called from a "sane" (read: can schedule)
+        * context for the sake of the low level drivers, except in the special
+        * case of oops_in_progress
+        */
+       if (!oops_in_progress)
+               might_sleep();
+
+       WARN_CONSOLE_UNLOCKED();
+
+       ignore_poke = 0;
+       if (!console_blanked)
+               return;
+       if (!vc_cons_allocated(fg_console)) {
+               /* impossible */
+               printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
+               return;
+       }
+       vc = vc_cons[fg_console].d;
+       /* Try to unblank in oops case too */
+       if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc))
+               return; /* but leave console_blanked != 0 */
+
+       if (blankinterval) {
+               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
+               blank_state = blank_normal_wait;
+       }
+
+       console_blanked = 0;
+       if (vc->vc_sw->con_blank(vc, 0, leaving_gfx) || vt_force_oops_output(vc))
+               /* Low-level driver cannot restore -> do it ourselves */
+               update_screen(vc);
+       if (console_blank_hook)
+               console_blank_hook(0);
+       set_palette(vc);
+       set_cursor(vc);
+       vt_event_post(VT_EVENT_UNBLANK, vc->vc_num, vc->vc_num);
+}
+EXPORT_SYMBOL(do_unblank_screen);
+
+/*
+ * This is called by the outside world to cause a forced unblank, mostly for
+ * oopses. Currently, I just call do_unblank_screen(0), but we could eventually
+ * call it with 1 as an argument and so force a mode restore... that may kill
+ * X or at least garbage the screen but would also make the Oops visible...
+ */
+void unblank_screen(void)
+{
+       do_unblank_screen(0);
+}
+
+/*
+ * We defer the timer blanking to work queue so it can take the console mutex
+ * (console operations can still happen at irq time, but only from printk which
+ * has the console mutex. Not perfect yet, but better than no locking
+ */
+static void blank_screen_t(unsigned long dummy)
+{
+       if (unlikely(!keventd_up())) {
+               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
+               return;
+       }
+       blank_timer_expired = 1;
+       schedule_work(&console_work);
+}
+
+void poke_blanked_console(void)
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       /* Add this so we quickly catch whoever might call us in a non
+        * safe context. Nowadays, unblank_screen() isn't to be called in
+        * atomic contexts and is allowed to schedule (with the special case
+        * of oops_in_progress, but that isn't of any concern for this
+        * function. --BenH.
+        */
+       might_sleep();
+
+       /* This isn't perfectly race free, but a race here would be mostly harmless,
+        * at worse, we'll do a spurrious blank and it's unlikely
+        */
+       del_timer(&console_timer);
+       blank_timer_expired = 0;
+
+       if (ignore_poke || !vc_cons[fg_console].d || vc_cons[fg_console].d->vc_mode == KD_GRAPHICS)
+               return;
+       if (console_blanked)
+               unblank_screen();
+       else if (blankinterval) {
+               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
+               blank_state = blank_normal_wait;
+       }
+}
+
+/*
+ *     Palettes
+ */
+
+static void set_palette(struct vc_data *vc)
+{
+       WARN_CONSOLE_UNLOCKED();
+
+       if (vc->vc_mode != KD_GRAPHICS)
+               vc->vc_sw->con_set_palette(vc, color_table);
+}
+
+static int set_get_cmap(unsigned char __user *arg, int set)
+{
+    int i, j, k;
+
+    WARN_CONSOLE_UNLOCKED();
+
+    for (i = 0; i < 16; i++)
+       if (set) {
+           get_user(default_red[i], arg++);
+           get_user(default_grn[i], arg++);
+           get_user(default_blu[i], arg++);
+       } else {
+           put_user(default_red[i], arg++);
+           put_user(default_grn[i], arg++);
+           put_user(default_blu[i], arg++);
+       }
+    if (set) {
+       for (i = 0; i < MAX_NR_CONSOLES; i++)
+           if (vc_cons_allocated(i)) {
+               for (j = k = 0; j < 16; j++) {
+                   vc_cons[i].d->vc_palette[k++] = default_red[j];
+                   vc_cons[i].d->vc_palette[k++] = default_grn[j];
+                   vc_cons[i].d->vc_palette[k++] = default_blu[j];
+               }
+               set_palette(vc_cons[i].d);
+           }
+    }
+    return 0;
+}
+
+/*
+ * Load palette into the DAC registers. arg points to a colour
+ * map, 3 bytes per colour, 16 colours, range from 0 to 255.
+ */
+
+int con_set_cmap(unsigned char __user *arg)
+{
+       int rc;
+
+       acquire_console_sem();
+       rc = set_get_cmap (arg,1);
+       release_console_sem();
+
+       return rc;
+}
+
+int con_get_cmap(unsigned char __user *arg)
+{
+       int rc;
+
+       acquire_console_sem();
+       rc = set_get_cmap (arg,0);
+       release_console_sem();
+
+       return rc;
+}
+
+void reset_palette(struct vc_data *vc)
+{
+       int j, k;
+       for (j=k=0; j<16; j++) {
+               vc->vc_palette[k++] = default_red[j];
+               vc->vc_palette[k++] = default_grn[j];
+               vc->vc_palette[k++] = default_blu[j];
+       }
+       set_palette(vc);
+}
+
+/*
+ *  Font switching
+ *
+ *  Currently we only support fonts up to 32 pixels wide, at a maximum height
+ *  of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints, 
+ *  depending on width) reserved for each character which is kinda wasty, but 
+ *  this is done in order to maintain compatibility with the EGA/VGA fonts. It 
+ *  is upto the actual low-level console-driver convert data into its favorite
+ *  format (maybe we should add a `fontoffset' field to the `display'
+ *  structure so we won't have to convert the fontdata all the time.
+ *  /Jes
+ */
+
+#define max_font_size 65536
+
+static int con_font_get(struct vc_data *vc, struct console_font_op *op)
+{
+       struct console_font font;
+       int rc = -EINVAL;
+       int c;
+
+       if (vc->vc_mode != KD_TEXT)
+               return -EINVAL;
+
+       if (op->data) {
+               font.data = kmalloc(max_font_size, GFP_KERNEL);
+               if (!font.data)
+                       return -ENOMEM;
+       } else
+               font.data = NULL;
+
+       acquire_console_sem();
+       if (vc->vc_sw->con_font_get)
+               rc = vc->vc_sw->con_font_get(vc, &font);
+       else
+               rc = -ENOSYS;
+       release_console_sem();
+
+       if (rc)
+               goto out;
+
+       c = (font.width+7)/8 * 32 * font.charcount;
+
+       if (op->data && font.charcount > op->charcount)
+               rc = -ENOSPC;
+       if (!(op->flags & KD_FONT_FLAG_OLD)) {
+               if (font.width > op->width || font.height > op->height) 
+                       rc = -ENOSPC;
+       } else {
+               if (font.width != 8)
+                       rc = -EIO;
+               else if ((op->height && font.height > op->height) ||
+                        font.height > 32)
+                       rc = -ENOSPC;
+       }
+       if (rc)
+               goto out;
+
+       op->height = font.height;
+       op->width = font.width;
+       op->charcount = font.charcount;
+
+       if (op->data && copy_to_user(op->data, font.data, c))
+               rc = -EFAULT;
+
+out:
+       kfree(font.data);
+       return rc;
+}
+
+static int con_font_set(struct vc_data *vc, struct console_font_op *op)
+{
+       struct console_font font;
+       int rc = -EINVAL;
+       int size;
+
+       if (vc->vc_mode != KD_TEXT)
+               return -EINVAL;
+       if (!op->data)
+               return -EINVAL;
+       if (op->charcount > 512)
+               return -EINVAL;
+       if (!op->height) {              /* Need to guess font height [compat] */
+               int h, i;
+               u8 __user *charmap = op->data;
+               u8 tmp;
+               
+               /* If from KDFONTOP ioctl, don't allow things which can be done in userland,
+                  so that we can get rid of this soon */
+               if (!(op->flags & KD_FONT_FLAG_OLD))
+                       return -EINVAL;
+               for (h = 32; h > 0; h--)
+                       for (i = 0; i < op->charcount; i++) {
+                               if (get_user(tmp, &charmap[32*i+h-1]))
+                                       return -EFAULT;
+                               if (tmp)
+                                       goto nonzero;
+                       }
+               return -EINVAL;
+       nonzero:
+               op->height = h;
+       }
+       if (op->width <= 0 || op->width > 32 || op->height > 32)
+               return -EINVAL;
+       size = (op->width+7)/8 * 32 * op->charcount;
+       if (size > max_font_size)
+               return -ENOSPC;
+       font.charcount = op->charcount;
+       font.height = op->height;
+       font.width = op->width;
+       font.data = memdup_user(op->data, size);
+       if (IS_ERR(font.data))
+               return PTR_ERR(font.data);
+       acquire_console_sem();
+       if (vc->vc_sw->con_font_set)
+               rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
+       else
+               rc = -ENOSYS;
+       release_console_sem();
+       kfree(font.data);
+       return rc;
+}
+
+static int con_font_default(struct vc_data *vc, struct console_font_op *op)
+{
+       struct console_font font = {.width = op->width, .height = op->height};
+       char name[MAX_FONT_NAME];
+       char *s = name;
+       int rc;
+
+       if (vc->vc_mode != KD_TEXT)
+               return -EINVAL;
+
+       if (!op->data)
+               s = NULL;
+       else if (strncpy_from_user(name, op->data, MAX_FONT_NAME - 1) < 0)
+               return -EFAULT;
+       else
+               name[MAX_FONT_NAME - 1] = 0;
+
+       acquire_console_sem();
+       if (vc->vc_sw->con_font_default)
+               rc = vc->vc_sw->con_font_default(vc, &font, s);
+       else
+               rc = -ENOSYS;
+       release_console_sem();
+       if (!rc) {
+               op->width = font.width;
+               op->height = font.height;
+       }
+       return rc;
+}
+
+static int con_font_copy(struct vc_data *vc, struct console_font_op *op)
+{
+       int con = op->height;
+       int rc;
+
+       if (vc->vc_mode != KD_TEXT)
+               return -EINVAL;
+
+       acquire_console_sem();
+       if (!vc->vc_sw->con_font_copy)
+               rc = -ENOSYS;
+       else if (con < 0 || !vc_cons_allocated(con))
+               rc = -ENOTTY;
+       else if (con == vc->vc_num)     /* nothing to do */
+               rc = 0;
+       else
+               rc = vc->vc_sw->con_font_copy(vc, con);
+       release_console_sem();
+       return rc;
+}
+
+int con_font_op(struct vc_data *vc, struct console_font_op *op)
+{
+       switch (op->op) {
+       case KD_FONT_OP_SET:
+               return con_font_set(vc, op);
+       case KD_FONT_OP_GET:
+               return con_font_get(vc, op);
+       case KD_FONT_OP_SET_DEFAULT:
+               return con_font_default(vc, op);
+       case KD_FONT_OP_COPY:
+               return con_font_copy(vc, op);
+       }
+       return -ENOSYS;
+}
+
+/*
+ *     Interface exported to selection and vcs.
+ */
+
+/* used by selection */
+u16 screen_glyph(struct vc_data *vc, int offset)
+{
+       u16 w = scr_readw(screenpos(vc, offset, 1));
+       u16 c = w & 0xff;
+
+       if (w & vc->vc_hi_font_mask)
+               c |= 0x100;
+       return c;
+}
+EXPORT_SYMBOL_GPL(screen_glyph);
+
+/* used by vcs - note the word offset */
+unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
+{
+       return screenpos(vc, 2 * w_offset, viewed);
+}
+
+void getconsxy(struct vc_data *vc, unsigned char *p)
+{
+       p[0] = vc->vc_x;
+       p[1] = vc->vc_y;
+}
+
+void putconsxy(struct vc_data *vc, unsigned char *p)
+{
+       hide_cursor(vc);
+       gotoxy(vc, p[0], p[1]);
+       set_cursor(vc);
+}
+
+u16 vcs_scr_readw(struct vc_data *vc, const u16 *org)
+{
+       if ((unsigned long)org == vc->vc_pos && softcursor_original != -1)
+               return softcursor_original;
+       return scr_readw(org);
+}
+
+void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org)
+{
+       scr_writew(val, org);
+       if ((unsigned long)org == vc->vc_pos) {
+               softcursor_original = -1;
+               add_softcursor(vc);
+       }
+}
+
+void vcs_scr_updated(struct vc_data *vc)
+{
+       notify_update(vc);
+}
+
+/*
+ *     Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(color_table);
+EXPORT_SYMBOL(default_red);
+EXPORT_SYMBOL(default_grn);
+EXPORT_SYMBOL(default_blu);
+EXPORT_SYMBOL(update_region);
+EXPORT_SYMBOL(redraw_screen);
+EXPORT_SYMBOL(vc_resize);
+EXPORT_SYMBOL(fg_console);
+EXPORT_SYMBOL(console_blank_hook);
+EXPORT_SYMBOL(console_blanked);
+EXPORT_SYMBOL(vc_cons);
+EXPORT_SYMBOL(global_cursor_default);
+#ifndef VT_SINGLE_DRIVER
+EXPORT_SYMBOL(take_over_console);
+EXPORT_SYMBOL(give_up_console);
+#endif
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
new file mode 100644 (file)
index 0000000..6b68a0f
--- /dev/null
@@ -0,0 +1,1788 @@
+/*
+ *  linux/drivers/char/vt_ioctl.c
+ *
+ *  Copyright (C) 1992 obz under the linux copyright
+ *
+ *  Dynamic diacritical handling - aeb@cwi.nl - Dec 1993
+ *  Dynamic keymap and string allocation - aeb@cwi.nl - May 1994
+ *  Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995
+ *  Some code moved for less code duplication - Andi Kleen - Mar 1997
+ *  Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+#include <linux/compat.h>
+#include <linux/module.h>
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/console.h>
+#include <linux/consolemap.h>
+#include <linux/signal.h>
+#include <linux/smp_lock.h>
+#include <linux/timex.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/kbd_diacr.h>
+#include <linux/selection.h>
+
+char vt_dont_switch;
+extern struct tty_driver *console_driver;
+
+#define VT_IS_IN_USE(i)        (console_driver->ttys[i] && console_driver->ttys[i]->count)
+#define VT_BUSY(i)     (VT_IS_IN_USE(i) || i == fg_console || vc_cons[i].d == sel_cons)
+
+/*
+ * Console (vt and kd) routines, as defined by USL SVR4 manual, and by
+ * experimentation and study of X386 SYSV handling.
+ *
+ * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and
+ * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console,
+ * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will
+ * always treat our set of vt as numbered 1..MAX_NR_CONSOLES (corresponding to
+ * ttys 0..MAX_NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using
+ * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing
+ * to the current console is done by the main ioctl code.
+ */
+
+#ifdef CONFIG_X86
+#include <linux/syscalls.h>
+#endif
+
+static void complete_change_console(struct vc_data *vc);
+
+/*
+ *     User space VT_EVENT handlers
+ */
+
+struct vt_event_wait {
+       struct list_head list;
+       struct vt_event event;
+       int done;
+};
+
+static LIST_HEAD(vt_events);
+static DEFINE_SPINLOCK(vt_event_lock);
+static DECLARE_WAIT_QUEUE_HEAD(vt_event_waitqueue);
+
+/**
+ *     vt_event_post
+ *     @event: the event that occurred
+ *     @old: old console
+ *     @new: new console
+ *
+ *     Post an VT event to interested VT handlers
+ */
+
+void vt_event_post(unsigned int event, unsigned int old, unsigned int new)
+{
+       struct list_head *pos, *head;
+       unsigned long flags;
+       int wake = 0;
+
+       spin_lock_irqsave(&vt_event_lock, flags);
+       head = &vt_events;
+
+       list_for_each(pos, head) {
+               struct vt_event_wait *ve = list_entry(pos,
+                                               struct vt_event_wait, list);
+               if (!(ve->event.event & event))
+                       continue;
+               ve->event.event = event;
+               /* kernel view is consoles 0..n-1, user space view is
+                  console 1..n with 0 meaning current, so we must bias */
+               ve->event.oldev = old + 1;
+               ve->event.newev = new + 1;
+               wake = 1;
+               ve->done = 1;
+       }
+       spin_unlock_irqrestore(&vt_event_lock, flags);
+       if (wake)
+               wake_up_interruptible(&vt_event_waitqueue);
+}
+
+/**
+ *     vt_event_wait           -       wait for an event
+ *     @vw: our event
+ *
+ *     Waits for an event to occur which completes our vt_event_wait
+ *     structure. On return the structure has wv->done set to 1 for success
+ *     or 0 if some event such as a signal ended the wait.
+ */
+
+static void vt_event_wait(struct vt_event_wait *vw)
+{
+       unsigned long flags;
+       /* Prepare the event */
+       INIT_LIST_HEAD(&vw->list);
+       vw->done = 0;
+       /* Queue our event */
+       spin_lock_irqsave(&vt_event_lock, flags);
+       list_add(&vw->list, &vt_events);
+       spin_unlock_irqrestore(&vt_event_lock, flags);
+       /* Wait for it to pass */
+       wait_event_interruptible_tty(vt_event_waitqueue, vw->done);
+       /* Dequeue it */
+       spin_lock_irqsave(&vt_event_lock, flags);
+       list_del(&vw->list);
+       spin_unlock_irqrestore(&vt_event_lock, flags);
+}
+
+/**
+ *     vt_event_wait_ioctl     -       event ioctl handler
+ *     @arg: argument to ioctl
+ *
+ *     Implement the VT_WAITEVENT ioctl using the VT event interface
+ */
+
+static int vt_event_wait_ioctl(struct vt_event __user *event)
+{
+       struct vt_event_wait vw;
+
+       if (copy_from_user(&vw.event, event, sizeof(struct vt_event)))
+               return -EFAULT;
+       /* Highest supported event for now */
+       if (vw.event.event & ~VT_MAX_EVENT)
+               return -EINVAL;
+
+       vt_event_wait(&vw);
+       /* If it occurred report it */
+       if (vw.done) {
+               if (copy_to_user(event, &vw.event, sizeof(struct vt_event)))
+                       return -EFAULT;
+               return 0;
+       }
+       return -EINTR;
+}
+
+/**
+ *     vt_waitactive   -       active console wait
+ *     @event: event code
+ *     @n: new console
+ *
+ *     Helper for event waits. Used to implement the legacy
+ *     event waiting ioctls in terms of events
+ */
+
+int vt_waitactive(int n)
+{
+       struct vt_event_wait vw;
+       do {
+               if (n == fg_console + 1)
+                       break;
+               vw.event.event = VT_EVENT_SWITCH;
+               vt_event_wait(&vw);
+               if (vw.done == 0)
+                       return -EINTR;
+       } while (vw.event.newev != n);
+       return 0;
+}
+
+/*
+ * these are the valid i/o ports we're allowed to change. they map all the
+ * video ports
+ */
+#define GPFIRST 0x3b4
+#define GPLAST 0x3df
+#define GPNUM (GPLAST - GPFIRST + 1)
+
+#define i (tmp.kb_index)
+#define s (tmp.kb_table)
+#define v (tmp.kb_value)
+static inline int
+do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd)
+{
+       struct kbentry tmp;
+       ushort *key_map, val, ov;
+
+       if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry)))
+               return -EFAULT;
+
+       if (!capable(CAP_SYS_TTY_CONFIG))
+               perm = 0;
+
+       switch (cmd) {
+       case KDGKBENT:
+               key_map = key_maps[s];
+               if (key_map) {
+                   val = U(key_map[i]);
+                   if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES)
+                       val = K_HOLE;
+               } else
+                   val = (i ? K_HOLE : K_NOSUCHMAP);
+               return put_user(val, &user_kbe->kb_value);
+       case KDSKBENT:
+               if (!perm)
+                       return -EPERM;
+               if (!i && v == K_NOSUCHMAP) {
+                       /* deallocate map */
+                       key_map = key_maps[s];
+                       if (s && key_map) {
+                           key_maps[s] = NULL;
+                           if (key_map[0] == U(K_ALLOCATED)) {
+                                       kfree(key_map);
+                                       keymap_count--;
+                           }
+                       }
+                       break;
+               }
+
+               if (KTYP(v) < NR_TYPES) {
+                   if (KVAL(v) > max_vals[KTYP(v)])
+                               return -EINVAL;
+               } else
+                   if (kbd->kbdmode != VC_UNICODE)
+                               return -EINVAL;
+
+               /* ++Geert: non-PC keyboards may generate keycode zero */
+#if !defined(__mc68000__) && !defined(__powerpc__)
+               /* assignment to entry 0 only tests validity of args */
+               if (!i)
+                       break;
+#endif
+
+               if (!(key_map = key_maps[s])) {
+                       int j;
+
+                       if (keymap_count >= MAX_NR_OF_USER_KEYMAPS &&
+                           !capable(CAP_SYS_RESOURCE))
+                               return -EPERM;
+
+                       key_map = kmalloc(sizeof(plain_map),
+                                                    GFP_KERNEL);
+                       if (!key_map)
+                               return -ENOMEM;
+                       key_maps[s] = key_map;
+                       key_map[0] = U(K_ALLOCATED);
+                       for (j = 1; j < NR_KEYS; j++)
+                               key_map[j] = U(K_HOLE);
+                       keymap_count++;
+               }
+               ov = U(key_map[i]);
+               if (v == ov)
+                       break;  /* nothing to do */
+               /*
+                * Attention Key.
+                */
+               if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               key_map[i] = U(v);
+               if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT))
+                       compute_shiftstate();
+               break;
+       }
+       return 0;
+}
+#undef i
+#undef s
+#undef v
+
+static inline int 
+do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm)
+{
+       struct kbkeycode tmp;
+       int kc = 0;
+
+       if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode)))
+               return -EFAULT;
+       switch (cmd) {
+       case KDGETKEYCODE:
+               kc = getkeycode(tmp.scancode);
+               if (kc >= 0)
+                       kc = put_user(kc, &user_kbkc->keycode);
+               break;
+       case KDSETKEYCODE:
+               if (!perm)
+                       return -EPERM;
+               kc = setkeycode(tmp.scancode, tmp.keycode);
+               break;
+       }
+       return kc;
+}
+
+static inline int
+do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
+{
+       struct kbsentry *kbs;
+       char *p;
+       u_char *q;
+       u_char __user *up;
+       int sz;
+       int delta;
+       char *first_free, *fj, *fnw;
+       int i, j, k;
+       int ret;
+
+       if (!capable(CAP_SYS_TTY_CONFIG))
+               perm = 0;
+
+       kbs = kmalloc(sizeof(*kbs), GFP_KERNEL);
+       if (!kbs) {
+               ret = -ENOMEM;
+               goto reterr;
+       }
+
+       /* we mostly copy too much here (512bytes), but who cares ;) */
+       if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) {
+               ret = -EFAULT;
+               goto reterr;
+       }
+       kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0';
+       i = kbs->kb_func;
+
+       switch (cmd) {
+       case KDGKBSENT:
+               sz = sizeof(kbs->kb_string) - 1; /* sz should have been
+                                                 a struct member */
+               up = user_kdgkb->kb_string;
+               p = func_table[i];
+               if(p)
+                       for ( ; *p && sz; p++, sz--)
+                               if (put_user(*p, up++)) {
+                                       ret = -EFAULT;
+                                       goto reterr;
+                               }
+               if (put_user('\0', up)) {
+                       ret = -EFAULT;
+                       goto reterr;
+               }
+               kfree(kbs);
+               return ((p && *p) ? -EOVERFLOW : 0);
+       case KDSKBSENT:
+               if (!perm) {
+                       ret = -EPERM;
+                       goto reterr;
+               }
+
+               q = func_table[i];
+               first_free = funcbufptr + (funcbufsize - funcbufleft);
+               for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) 
+                       ;
+               if (j < MAX_NR_FUNC)
+                       fj = func_table[j];
+               else
+                       fj = first_free;
+
+               delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
+               if (delta <= funcbufleft) {     /* it fits in current buf */
+                   if (j < MAX_NR_FUNC) {
+                       memmove(fj + delta, fj, first_free - fj);
+                       for (k = j; k < MAX_NR_FUNC; k++)
+                           if (func_table[k])
+                               func_table[k] += delta;
+                   }
+                   if (!q)
+                     func_table[i] = fj;
+                   funcbufleft -= delta;
+               } else {                        /* allocate a larger buffer */
+                   sz = 256;
+                   while (sz < funcbufsize - funcbufleft + delta)
+                     sz <<= 1;
+                   fnw = kmalloc(sz, GFP_KERNEL);
+                   if(!fnw) {
+                     ret = -ENOMEM;
+                     goto reterr;
+                   }
+
+                   if (!q)
+                     func_table[i] = fj;
+                   if (fj > funcbufptr)
+                       memmove(fnw, funcbufptr, fj - funcbufptr);
+                   for (k = 0; k < j; k++)
+                     if (func_table[k])
+                       func_table[k] = fnw + (func_table[k] - funcbufptr);
+
+                   if (first_free > fj) {
+                       memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
+                       for (k = j; k < MAX_NR_FUNC; k++)
+                         if (func_table[k])
+                           func_table[k] = fnw + (func_table[k] - funcbufptr) + delta;
+                   }
+                   if (funcbufptr != func_buf)
+                     kfree(funcbufptr);
+                   funcbufptr = fnw;
+                   funcbufleft = funcbufleft - delta + sz - funcbufsize;
+                   funcbufsize = sz;
+               }
+               strcpy(func_table[i], kbs->kb_string);
+               break;
+       }
+       ret = 0;
+reterr:
+       kfree(kbs);
+       return ret;
+}
+
+static inline int 
+do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op)
+{
+       struct consolefontdesc cfdarg;
+       int i;
+
+       if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) 
+               return -EFAULT;
+       
+       switch (cmd) {
+       case PIO_FONTX:
+               if (!perm)
+                       return -EPERM;
+               op->op = KD_FONT_OP_SET;
+               op->flags = KD_FONT_FLAG_OLD;
+               op->width = 8;
+               op->height = cfdarg.charheight;
+               op->charcount = cfdarg.charcount;
+               op->data = cfdarg.chardata;
+               return con_font_op(vc_cons[fg_console].d, op);
+       case GIO_FONTX: {
+               op->op = KD_FONT_OP_GET;
+               op->flags = KD_FONT_FLAG_OLD;
+               op->width = 8;
+               op->height = cfdarg.charheight;
+               op->charcount = cfdarg.charcount;
+               op->data = cfdarg.chardata;
+               i = con_font_op(vc_cons[fg_console].d, op);
+               if (i)
+                       return i;
+               cfdarg.charheight = op->height;
+               cfdarg.charcount = op->charcount;
+               if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc)))
+                       return -EFAULT;
+               return 0;
+               }
+       }
+       return -EINVAL;
+}
+
+static inline int 
+do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_data *vc)
+{
+       struct unimapdesc tmp;
+
+       if (copy_from_user(&tmp, user_ud, sizeof tmp))
+               return -EFAULT;
+       if (tmp.entries)
+               if (!access_ok(VERIFY_WRITE, tmp.entries,
+                               tmp.entry_ct*sizeof(struct unipair)))
+                       return -EFAULT;
+       switch (cmd) {
+       case PIO_UNIMAP:
+               if (!perm)
+                       return -EPERM;
+               return con_set_unimap(vc, tmp.entry_ct, tmp.entries);
+       case GIO_UNIMAP:
+               if (!perm && fg_console != vc->vc_num)
+                       return -EPERM;
+               return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp.entries);
+       }
+       return 0;
+}
+
+
+
+/*
+ * We handle the console-specific ioctl's here.  We allow the
+ * capability to modify any console, not just the fg_console. 
+ */
+int vt_ioctl(struct tty_struct *tty, struct file * file,
+            unsigned int cmd, unsigned long arg)
+{
+       struct vc_data *vc = tty->driver_data;
+       struct console_font_op op;      /* used in multiple places here */
+       struct kbd_struct * kbd;
+       unsigned int console;
+       unsigned char ucval;
+       unsigned int uival;
+       void __user *up = (void __user *)arg;
+       int i, perm;
+       int ret = 0;
+
+       console = vc->vc_num;
+
+       tty_lock();
+
+       if (!vc_cons_allocated(console)) {      /* impossible? */
+               ret = -ENOIOCTLCMD;
+               goto out;
+       }
+
+
+       /*
+        * To have permissions to do most of the vt ioctls, we either have
+        * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
+        */
+       perm = 0;
+       if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
+               perm = 1;
+       kbd = kbd_table + console;
+       switch (cmd) {
+       case TIOCLINUX:
+               ret = tioclinux(tty, arg);
+               break;
+       case KIOCSOUND:
+               if (!perm)
+                       goto eperm;
+               /*
+                * The use of PIT_TICK_RATE is historic, it used to be
+                * the platform-dependent CLOCK_TICK_RATE between 2.6.12
+                * and 2.6.36, which was a minor but unfortunate ABI
+                * change.
+                */
+               if (arg)
+                       arg = PIT_TICK_RATE / arg;
+               kd_mksound(arg, 0);
+               break;
+
+       case KDMKTONE:
+               if (!perm)
+                       goto eperm;
+       {
+               unsigned int ticks, count;
+               
+               /*
+                * Generate the tone for the appropriate number of ticks.
+                * If the time is zero, turn off sound ourselves.
+                */
+               ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
+               count = ticks ? (arg & 0xffff) : 0;
+               if (count)
+                       count = PIT_TICK_RATE / count;
+               kd_mksound(count, ticks);
+               break;
+       }
+
+       case KDGKBTYPE:
+               /*
+                * this is naive.
+                */
+               ucval = KB_101;
+               goto setchar;
+
+               /*
+                * These cannot be implemented on any machine that implements
+                * ioperm() in user level (such as Alpha PCs) or not at all.
+                *
+                * XXX: you should never use these, just call ioperm directly..
+                */
+#ifdef CONFIG_X86
+       case KDADDIO:
+       case KDDELIO:
+               /*
+                * KDADDIO and KDDELIO may be able to add ports beyond what
+                * we reject here, but to be safe...
+                */
+               if (arg < GPFIRST || arg > GPLAST) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
+               break;
+
+       case KDENABIO:
+       case KDDISABIO:
+               ret = sys_ioperm(GPFIRST, GPNUM,
+                                 (cmd == KDENABIO)) ? -ENXIO : 0;
+               break;
+#endif
+
+       /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */
+               
+       case KDKBDREP:
+       {
+               struct kbd_repeat kbrep;
+               
+               if (!capable(CAP_SYS_TTY_CONFIG))
+                       goto eperm;
+
+               if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) {
+                       ret =  -EFAULT;
+                       break;
+               }
+               ret = kbd_rate(&kbrep);
+               if (ret)
+                       break;
+               if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat)))
+                       ret = -EFAULT;
+               break;
+       }
+
+       case KDSETMODE:
+               /*
+                * currently, setting the mode from KD_TEXT to KD_GRAPHICS
+                * doesn't do a whole lot. i'm not sure if it should do any
+                * restoration of modes or what...
+                *
+                * XXX It should at least call into the driver, fbdev's definitely
+                * need to restore their engine state. --BenH
+                */
+               if (!perm)
+                       goto eperm;
+               switch (arg) {
+               case KD_GRAPHICS:
+                       break;
+               case KD_TEXT0:
+               case KD_TEXT1:
+                       arg = KD_TEXT;
+               case KD_TEXT:
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto out;
+               }
+               if (vc->vc_mode == (unsigned char) arg)
+                       break;
+               vc->vc_mode = (unsigned char) arg;
+               if (console != fg_console)
+                       break;
+               /*
+                * explicitly blank/unblank the screen if switching modes
+                */
+               acquire_console_sem();
+               if (arg == KD_TEXT)
+                       do_unblank_screen(1);
+               else
+                       do_blank_screen(1);
+               release_console_sem();
+               break;
+
+       case KDGETMODE:
+               uival = vc->vc_mode;
+               goto setint;
+
+       case KDMAPDISP:
+       case KDUNMAPDISP:
+               /*
+                * these work like a combination of mmap and KDENABIO.
+                * this could be easily finished.
+                */
+               ret = -EINVAL;
+               break;
+
+       case KDSKBMODE:
+               if (!perm)
+                       goto eperm;
+               switch(arg) {
+                 case K_RAW:
+                       kbd->kbdmode = VC_RAW;
+                       break;
+                 case K_MEDIUMRAW:
+                       kbd->kbdmode = VC_MEDIUMRAW;
+                       break;
+                 case K_XLATE:
+                       kbd->kbdmode = VC_XLATE;
+                       compute_shiftstate();
+                       break;
+                 case K_UNICODE:
+                       kbd->kbdmode = VC_UNICODE;
+                       compute_shiftstate();
+                       break;
+                 default:
+                       ret = -EINVAL;
+                       goto out;
+               }
+               tty_ldisc_flush(tty);
+               break;
+
+       case KDGKBMODE:
+               uival = ((kbd->kbdmode == VC_RAW) ? K_RAW :
+                                (kbd->kbdmode == VC_MEDIUMRAW) ? K_MEDIUMRAW :
+                                (kbd->kbdmode == VC_UNICODE) ? K_UNICODE :
+                                K_XLATE);
+               goto setint;
+
+       /* this could be folded into KDSKBMODE, but for compatibility
+          reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
+       case KDSKBMETA:
+               switch(arg) {
+                 case K_METABIT:
+                       clr_vc_kbd_mode(kbd, VC_META);
+                       break;
+                 case K_ESCPREFIX:
+                       set_vc_kbd_mode(kbd, VC_META);
+                       break;
+                 default:
+                       ret = -EINVAL;
+               }
+               break;
+
+       case KDGKBMETA:
+               uival = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
+       setint:
+               ret = put_user(uival, (int __user *)arg);
+               break;
+
+       case KDGETKEYCODE:
+       case KDSETKEYCODE:
+               if(!capable(CAP_SYS_TTY_CONFIG))
+                       perm = 0;
+               ret = do_kbkeycode_ioctl(cmd, up, perm);
+               break;
+
+       case KDGKBENT:
+       case KDSKBENT:
+               ret = do_kdsk_ioctl(cmd, up, perm, kbd);
+               break;
+
+       case KDGKBSENT:
+       case KDSKBSENT:
+               ret = do_kdgkb_ioctl(cmd, up, perm);
+               break;
+
+       case KDGKBDIACR:
+       {
+               struct kbdiacrs __user *a = up;
+               struct kbdiacr diacr;
+               int i;
+
+               if (put_user(accent_table_size, &a->kb_cnt)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               for (i = 0; i < accent_table_size; i++) {
+                       diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr);
+                       diacr.base = conv_uni_to_8bit(accent_table[i].base);
+                       diacr.result = conv_uni_to_8bit(accent_table[i].result);
+                       if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) {
+                               ret = -EFAULT;
+                               break;
+                       }
+               }
+               break;
+       }
+       case KDGKBDIACRUC:
+       {
+               struct kbdiacrsuc __user *a = up;
+
+               if (put_user(accent_table_size, &a->kb_cnt))
+                       ret = -EFAULT;
+               else if (copy_to_user(a->kbdiacruc, accent_table,
+                               accent_table_size*sizeof(struct kbdiacruc)))
+                       ret = -EFAULT;
+               break;
+       }
+
+       case KDSKBDIACR:
+       {
+               struct kbdiacrs __user *a = up;
+               struct kbdiacr diacr;
+               unsigned int ct;
+               int i;
+
+               if (!perm)
+                       goto eperm;
+               if (get_user(ct,&a->kb_cnt)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (ct >= MAX_DIACR) {
+                       ret = -EINVAL;
+                       break;
+               }
+               accent_table_size = ct;
+               for (i = 0; i < ct; i++) {
+                       if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) {
+                               ret = -EFAULT;
+                               break;
+                       }
+                       accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr);
+                       accent_table[i].base = conv_8bit_to_uni(diacr.base);
+                       accent_table[i].result = conv_8bit_to_uni(diacr.result);
+               }
+               break;
+       }
+
+       case KDSKBDIACRUC:
+       {
+               struct kbdiacrsuc __user *a = up;
+               unsigned int ct;
+
+               if (!perm)
+                       goto eperm;
+               if (get_user(ct,&a->kb_cnt)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (ct >= MAX_DIACR) {
+                       ret = -EINVAL;
+                       break;
+               }
+               accent_table_size = ct;
+               if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc)))
+                       ret = -EFAULT;
+               break;
+       }
+
+       /* the ioctls below read/set the flags usually shown in the leds */
+       /* don't use them - they will go away without warning */
+       case KDGKBLED:
+               ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4);
+               goto setchar;
+
+       case KDSKBLED:
+               if (!perm)
+                       goto eperm;
+               if (arg & ~0x77) {
+                       ret = -EINVAL;
+                       break;
+               }
+               kbd->ledflagstate = (arg & 7);
+               kbd->default_ledflagstate = ((arg >> 4) & 7);
+               set_leds();
+               break;
+
+       /* the ioctls below only set the lights, not the functions */
+       /* for those, see KDGKBLED and KDSKBLED above */
+       case KDGETLED:
+               ucval = getledstate();
+       setchar:
+               ret = put_user(ucval, (char __user *)arg);
+               break;
+
+       case KDSETLED:
+               if (!perm)
+                       goto eperm;
+               setledstate(kbd, arg);
+               break;
+
+       /*
+        * A process can indicate its willingness to accept signals
+        * generated by pressing an appropriate key combination.
+        * Thus, one can have a daemon that e.g. spawns a new console
+        * upon a keypress and then changes to it.
+        * See also the kbrequest field of inittab(5).
+        */
+       case KDSIGACCEPT:
+       {
+               if (!perm || !capable(CAP_KILL))
+                       goto eperm;
+               if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
+                       ret = -EINVAL;
+               else {
+                       spin_lock_irq(&vt_spawn_con.lock);
+                       put_pid(vt_spawn_con.pid);
+                       vt_spawn_con.pid = get_pid(task_pid(current));
+                       vt_spawn_con.sig = arg;
+                       spin_unlock_irq(&vt_spawn_con.lock);
+               }
+               break;
+       }
+
+       case VT_SETMODE:
+       {
+               struct vt_mode tmp;
+
+               if (!perm)
+                       goto eperm;
+               if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+               if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+               acquire_console_sem();
+               vc->vt_mode = tmp;
+               /* the frsig is ignored, so we set it to 0 */
+               vc->vt_mode.frsig = 0;
+               put_pid(vc->vt_pid);
+               vc->vt_pid = get_pid(task_pid(current));
+               /* no switch is required -- saw@shade.msu.ru */
+               vc->vt_newvt = -1;
+               release_console_sem();
+               break;
+       }
+
+       case VT_GETMODE:
+       {
+               struct vt_mode tmp;
+               int rc;
+
+               acquire_console_sem();
+               memcpy(&tmp, &vc->vt_mode, sizeof(struct vt_mode));
+               release_console_sem();
+
+               rc = copy_to_user(up, &tmp, sizeof(struct vt_mode));
+               if (rc)
+                       ret = -EFAULT;
+               break;
+       }
+
+       /*
+        * Returns global vt state. Note that VT 0 is always open, since
+        * it's an alias for the current VT, and people can't use it here.
+        * We cannot return state for more than 16 VTs, since v_state is short.
+        */
+       case VT_GETSTATE:
+       {
+               struct vt_stat __user *vtstat = up;
+               unsigned short state, mask;
+
+               if (put_user(fg_console + 1, &vtstat->v_active))
+                       ret = -EFAULT;
+               else {
+                       state = 1;      /* /dev/tty0 is always open */
+                       for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask;
+                                                       ++i, mask <<= 1)
+                               if (VT_IS_IN_USE(i))
+                                       state |= mask;
+                       ret = put_user(state, &vtstat->v_state);
+               }
+               break;
+       }
+
+       /*
+        * Returns the first available (non-opened) console.
+        */
+       case VT_OPENQRY:
+               for (i = 0; i < MAX_NR_CONSOLES; ++i)
+                       if (! VT_IS_IN_USE(i))
+                               break;
+               uival = i < MAX_NR_CONSOLES ? (i+1) : -1;
+               goto setint;             
+
+       /*
+        * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num,
+        * with num >= 1 (switches to vt 0, our console, are not allowed, just
+        * to preserve sanity).
+        */
+       case VT_ACTIVATE:
+               if (!perm)
+                       goto eperm;
+               if (arg == 0 || arg > MAX_NR_CONSOLES)
+                       ret =  -ENXIO;
+               else {
+                       arg--;
+                       acquire_console_sem();
+                       ret = vc_allocate(arg);
+                       release_console_sem();
+                       if (ret)
+                               break;
+                       set_console(arg);
+               }
+               break;
+
+       case VT_SETACTIVATE:
+       {
+               struct vt_setactivate vsa;
+
+               if (!perm)
+                       goto eperm;
+
+               if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg,
+                                       sizeof(struct vt_setactivate))) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+               if (vsa.console == 0 || vsa.console > MAX_NR_CONSOLES)
+                       ret = -ENXIO;
+               else {
+                       vsa.console--;
+                       acquire_console_sem();
+                       ret = vc_allocate(vsa.console);
+                       if (ret == 0) {
+                               struct vc_data *nvc;
+                               /* This is safe providing we don't drop the
+                                  console sem between vc_allocate and
+                                  finishing referencing nvc */
+                               nvc = vc_cons[vsa.console].d;
+                               nvc->vt_mode = vsa.mode;
+                               nvc->vt_mode.frsig = 0;
+                               put_pid(nvc->vt_pid);
+                               nvc->vt_pid = get_pid(task_pid(current));
+                       }
+                       release_console_sem();
+                       if (ret)
+                               break;
+                       /* Commence switch and lock */
+                       set_console(arg);
+               }
+       }
+
+       /*
+        * wait until the specified VT has been activated
+        */
+       case VT_WAITACTIVE:
+               if (!perm)
+                       goto eperm;
+               if (arg == 0 || arg > MAX_NR_CONSOLES)
+                       ret = -ENXIO;
+               else
+                       ret = vt_waitactive(arg);
+               break;
+
+       /*
+        * If a vt is under process control, the kernel will not switch to it
+        * immediately, but postpone the operation until the process calls this
+        * ioctl, allowing the switch to complete.
+        *
+        * According to the X sources this is the behavior:
+        *      0:      pending switch-from not OK
+        *      1:      pending switch-from OK
+        *      2:      completed switch-to OK
+        */
+       case VT_RELDISP:
+               if (!perm)
+                       goto eperm;
+
+               if (vc->vt_mode.mode != VT_PROCESS) {
+                       ret = -EINVAL;
+                       break;
+               }
+               /*
+                * Switching-from response
+                */
+               acquire_console_sem();
+               if (vc->vt_newvt >= 0) {
+                       if (arg == 0)
+                               /*
+                                * Switch disallowed, so forget we were trying
+                                * to do it.
+                                */
+                               vc->vt_newvt = -1;
+
+                       else {
+                               /*
+                                * The current vt has been released, so
+                                * complete the switch.
+                                */
+                               int newvt;
+                               newvt = vc->vt_newvt;
+                               vc->vt_newvt = -1;
+                               ret = vc_allocate(newvt);
+                               if (ret) {
+                                       release_console_sem();
+                                       break;
+                               }
+                               /*
+                                * When we actually do the console switch,
+                                * make sure we are atomic with respect to
+                                * other console switches..
+                                */
+                               complete_change_console(vc_cons[newvt].d);
+                       }
+               } else {
+                       /*
+                        * Switched-to response
+                        */
+                       /*
+                        * If it's just an ACK, ignore it
+                        */
+                       if (arg != VT_ACKACQ)
+                               ret = -EINVAL;
+               }
+               release_console_sem();
+               break;
+
+        /*
+         * Disallocate memory associated to VT (but leave VT1)
+         */
+        case VT_DISALLOCATE:
+               if (arg > MAX_NR_CONSOLES) {
+                       ret = -ENXIO;
+                       break;
+               }
+               if (arg == 0) {
+                   /* deallocate all unused consoles, but leave 0 */
+                       acquire_console_sem();
+                       for (i=1; i<MAX_NR_CONSOLES; i++)
+                               if (! VT_BUSY(i))
+                                       vc_deallocate(i);
+                       release_console_sem();
+               } else {
+                       /* deallocate a single console, if possible */
+                       arg--;
+                       if (VT_BUSY(arg))
+                               ret = -EBUSY;
+                       else if (arg) {                       /* leave 0 */
+                               acquire_console_sem();
+                               vc_deallocate(arg);
+                               release_console_sem();
+                       }
+               }
+               break;
+
+       case VT_RESIZE:
+       {
+               struct vt_sizes __user *vtsizes = up;
+               struct vc_data *vc;
+
+               ushort ll,cc;
+               if (!perm)
+                       goto eperm;
+               if (get_user(ll, &vtsizes->v_rows) ||
+                   get_user(cc, &vtsizes->v_cols))
+                       ret = -EFAULT;
+               else {
+                       acquire_console_sem();
+                       for (i = 0; i < MAX_NR_CONSOLES; i++) {
+                               vc = vc_cons[i].d;
+
+                               if (vc) {
+                                       vc->vc_resize_user = 1;
+                                       vc_resize(vc_cons[i].d, cc, ll);
+                               }
+                       }
+                       release_console_sem();
+               }
+               break;
+       }
+
+       case VT_RESIZEX:
+       {
+               struct vt_consize __user *vtconsize = up;
+               ushort ll,cc,vlin,clin,vcol,ccol;
+               if (!perm)
+                       goto eperm;
+               if (!access_ok(VERIFY_READ, vtconsize,
+                               sizeof(struct vt_consize))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               /* FIXME: Should check the copies properly */
+               __get_user(ll, &vtconsize->v_rows);
+               __get_user(cc, &vtconsize->v_cols);
+               __get_user(vlin, &vtconsize->v_vlin);
+               __get_user(clin, &vtconsize->v_clin);
+               __get_user(vcol, &vtconsize->v_vcol);
+               __get_user(ccol, &vtconsize->v_ccol);
+               vlin = vlin ? vlin : vc->vc_scan_lines;
+               if (clin) {
+                       if (ll) {
+                               if (ll != vlin/clin) {
+                                       /* Parameters don't add up */
+                                       ret = -EINVAL;
+                                       break;
+                               }
+                       } else 
+                               ll = vlin/clin;
+               }
+               if (vcol && ccol) {
+                       if (cc) {
+                               if (cc != vcol/ccol) {
+                                       ret = -EINVAL;
+                                       break;
+                               }
+                       } else
+                               cc = vcol/ccol;
+               }
+
+               if (clin > 32) {
+                       ret =  -EINVAL;
+                       break;
+               }
+                   
+               for (i = 0; i < MAX_NR_CONSOLES; i++) {
+                       if (!vc_cons[i].d)
+                               continue;
+                       acquire_console_sem();
+                       if (vlin)
+                               vc_cons[i].d->vc_scan_lines = vlin;
+                       if (clin)
+                               vc_cons[i].d->vc_font.height = clin;
+                       vc_cons[i].d->vc_resize_user = 1;
+                       vc_resize(vc_cons[i].d, cc, ll);
+                       release_console_sem();
+               }
+               break;
+       }
+
+       case PIO_FONT: {
+               if (!perm)
+                       goto eperm;
+               op.op = KD_FONT_OP_SET;
+               op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */
+               op.width = 8;
+               op.height = 0;
+               op.charcount = 256;
+               op.data = up;
+               ret = con_font_op(vc_cons[fg_console].d, &op);
+               break;
+       }
+
+       case GIO_FONT: {
+               op.op = KD_FONT_OP_GET;
+               op.flags = KD_FONT_FLAG_OLD;
+               op.width = 8;
+               op.height = 32;
+               op.charcount = 256;
+               op.data = up;
+               ret = con_font_op(vc_cons[fg_console].d, &op);
+               break;
+       }
+
+       case PIO_CMAP:
+                if (!perm)
+                       ret = -EPERM;
+               else
+                       ret = con_set_cmap(up);
+               break;
+
+       case GIO_CMAP:
+                ret = con_get_cmap(up);
+               break;
+
+       case PIO_FONTX:
+       case GIO_FONTX:
+               ret = do_fontx_ioctl(cmd, up, perm, &op);
+               break;
+
+       case PIO_FONTRESET:
+       {
+               if (!perm)
+                       goto eperm;
+
+#ifdef BROKEN_GRAPHICS_PROGRAMS
+               /* With BROKEN_GRAPHICS_PROGRAMS defined, the default
+                  font is not saved. */
+               ret = -ENOSYS;
+               break;
+#else
+               {
+               op.op = KD_FONT_OP_SET_DEFAULT;
+               op.data = NULL;
+               ret = con_font_op(vc_cons[fg_console].d, &op);
+               if (ret)
+                       break;
+               con_set_default_unimap(vc_cons[fg_console].d);
+               break;
+               }
+#endif
+       }
+
+       case KDFONTOP: {
+               if (copy_from_user(&op, up, sizeof(op))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if (!perm && op.op != KD_FONT_OP_GET)
+                       goto eperm;
+               ret = con_font_op(vc, &op);
+               if (ret)
+                       break;
+               if (copy_to_user(up, &op, sizeof(op)))
+                       ret = -EFAULT;
+               break;
+       }
+
+       case PIO_SCRNMAP:
+               if (!perm)
+                       ret = -EPERM;
+               else
+                       ret = con_set_trans_old(up);
+               break;
+
+       case GIO_SCRNMAP:
+               ret = con_get_trans_old(up);
+               break;
+
+       case PIO_UNISCRNMAP:
+               if (!perm)
+                       ret = -EPERM;
+               else
+                       ret = con_set_trans_new(up);
+               break;
+
+       case GIO_UNISCRNMAP:
+               ret = con_get_trans_new(up);
+               break;
+
+       case PIO_UNIMAPCLR:
+             { struct unimapinit ui;
+               if (!perm)
+                       goto eperm;
+               ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
+               if (ret)
+                       ret = -EFAULT;
+               else
+                       con_clear_unimap(vc, &ui);
+               break;
+             }
+
+       case PIO_UNIMAP:
+       case GIO_UNIMAP:
+               ret = do_unimap_ioctl(cmd, up, perm, vc);
+               break;
+
+       case VT_LOCKSWITCH:
+               if (!capable(CAP_SYS_TTY_CONFIG))
+                       goto eperm;
+               vt_dont_switch = 1;
+               break;
+       case VT_UNLOCKSWITCH:
+               if (!capable(CAP_SYS_TTY_CONFIG))
+                       goto eperm;
+               vt_dont_switch = 0;
+               break;
+       case VT_GETHIFONTMASK:
+               ret = put_user(vc->vc_hi_font_mask,
+                                       (unsigned short __user *)arg);
+               break;
+       case VT_WAITEVENT:
+               ret = vt_event_wait_ioctl((struct vt_event __user *)arg);
+               break;
+       default:
+               ret = -ENOIOCTLCMD;
+       }
+out:
+       tty_unlock();
+       return ret;
+eperm:
+       ret = -EPERM;
+       goto out;
+}
+
+void reset_vc(struct vc_data *vc)
+{
+       vc->vc_mode = KD_TEXT;
+       kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
+       vc->vt_mode.mode = VT_AUTO;
+       vc->vt_mode.waitv = 0;
+       vc->vt_mode.relsig = 0;
+       vc->vt_mode.acqsig = 0;
+       vc->vt_mode.frsig = 0;
+       put_pid(vc->vt_pid);
+       vc->vt_pid = NULL;
+       vc->vt_newvt = -1;
+       if (!in_interrupt())    /* Via keyboard.c:SAK() - akpm */
+               reset_palette(vc);
+}
+
+void vc_SAK(struct work_struct *work)
+{
+       struct vc *vc_con =
+               container_of(work, struct vc, SAK_work);
+       struct vc_data *vc;
+       struct tty_struct *tty;
+
+       acquire_console_sem();
+       vc = vc_con->d;
+       if (vc) {
+               tty = vc->port.tty;
+               /*
+                * SAK should also work in all raw modes and reset
+                * them properly.
+                */
+               if (tty)
+                       __do_SAK(tty);
+               reset_vc(vc);
+       }
+       release_console_sem();
+}
+
+#ifdef CONFIG_COMPAT
+
+struct compat_consolefontdesc {
+       unsigned short charcount;       /* characters in font (256 or 512) */
+       unsigned short charheight;      /* scan lines per character (1-32) */
+       compat_caddr_t chardata;        /* font data in expanded form */
+};
+
+static inline int
+compat_fontx_ioctl(int cmd, struct compat_consolefontdesc __user *user_cfd,
+                        int perm, struct console_font_op *op)
+{
+       struct compat_consolefontdesc cfdarg;
+       int i;
+
+       if (copy_from_user(&cfdarg, user_cfd, sizeof(struct compat_consolefontdesc)))
+               return -EFAULT;
+
+       switch (cmd) {
+       case PIO_FONTX:
+               if (!perm)
+                       return -EPERM;
+               op->op = KD_FONT_OP_SET;
+               op->flags = KD_FONT_FLAG_OLD;
+               op->width = 8;
+               op->height = cfdarg.charheight;
+               op->charcount = cfdarg.charcount;
+               op->data = compat_ptr(cfdarg.chardata);
+               return con_font_op(vc_cons[fg_console].d, op);
+       case GIO_FONTX:
+               op->op = KD_FONT_OP_GET;
+               op->flags = KD_FONT_FLAG_OLD;
+               op->width = 8;
+               op->height = cfdarg.charheight;
+               op->charcount = cfdarg.charcount;
+               op->data = compat_ptr(cfdarg.chardata);
+               i = con_font_op(vc_cons[fg_console].d, op);
+               if (i)
+                       return i;
+               cfdarg.charheight = op->height;
+               cfdarg.charcount = op->charcount;
+               if (copy_to_user(user_cfd, &cfdarg, sizeof(struct compat_consolefontdesc)))
+                       return -EFAULT;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+struct compat_console_font_op {
+       compat_uint_t op;        /* operation code KD_FONT_OP_* */
+       compat_uint_t flags;     /* KD_FONT_FLAG_* */
+       compat_uint_t width, height;     /* font size */
+       compat_uint_t charcount;
+       compat_caddr_t data;    /* font data with height fixed to 32 */
+};
+
+static inline int
+compat_kdfontop_ioctl(struct compat_console_font_op __user *fontop,
+                        int perm, struct console_font_op *op, struct vc_data *vc)
+{
+       int i;
+
+       if (copy_from_user(op, fontop, sizeof(struct compat_console_font_op)))
+               return -EFAULT;
+       if (!perm && op->op != KD_FONT_OP_GET)
+               return -EPERM;
+       op->data = compat_ptr(((struct compat_console_font_op *)op)->data);
+       op->flags |= KD_FONT_FLAG_OLD;
+       i = con_font_op(vc, op);
+       if (i)
+               return i;
+       ((struct compat_console_font_op *)op)->data = (unsigned long)op->data;
+       if (copy_to_user(fontop, op, sizeof(struct compat_console_font_op)))
+               return -EFAULT;
+       return 0;
+}
+
+struct compat_unimapdesc {
+       unsigned short entry_ct;
+       compat_caddr_t entries;
+};
+
+static inline int
+compat_unimap_ioctl(unsigned int cmd, struct compat_unimapdesc __user *user_ud,
+                        int perm, struct vc_data *vc)
+{
+       struct compat_unimapdesc tmp;
+       struct unipair __user *tmp_entries;
+
+       if (copy_from_user(&tmp, user_ud, sizeof tmp))
+               return -EFAULT;
+       tmp_entries = compat_ptr(tmp.entries);
+       if (tmp_entries)
+               if (!access_ok(VERIFY_WRITE, tmp_entries,
+                               tmp.entry_ct*sizeof(struct unipair)))
+                       return -EFAULT;
+       switch (cmd) {
+       case PIO_UNIMAP:
+               if (!perm)
+                       return -EPERM;
+               return con_set_unimap(vc, tmp.entry_ct, tmp_entries);
+       case GIO_UNIMAP:
+               if (!perm && fg_console != vc->vc_num)
+                       return -EPERM;
+               return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), tmp_entries);
+       }
+       return 0;
+}
+
+long vt_compat_ioctl(struct tty_struct *tty, struct file * file,
+            unsigned int cmd, unsigned long arg)
+{
+       struct vc_data *vc = tty->driver_data;
+       struct console_font_op op;      /* used in multiple places here */
+       struct kbd_struct *kbd;
+       unsigned int console;
+       void __user *up = (void __user *)arg;
+       int perm;
+       int ret = 0;
+
+       console = vc->vc_num;
+
+       tty_lock();
+
+       if (!vc_cons_allocated(console)) {      /* impossible? */
+               ret = -ENOIOCTLCMD;
+               goto out;
+       }
+
+       /*
+        * To have permissions to do most of the vt ioctls, we either have
+        * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
+        */
+       perm = 0;
+       if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG))
+               perm = 1;
+
+       kbd = kbd_table + console;
+       switch (cmd) {
+       /*
+        * these need special handlers for incompatible data structures
+        */
+       case PIO_FONTX:
+       case GIO_FONTX:
+               ret = compat_fontx_ioctl(cmd, up, perm, &op);
+               break;
+
+       case KDFONTOP:
+               ret = compat_kdfontop_ioctl(up, perm, &op, vc);
+               break;
+
+       case PIO_UNIMAP:
+       case GIO_UNIMAP:
+               ret = compat_unimap_ioctl(cmd, up, perm, vc);
+               break;
+
+       /*
+        * all these treat 'arg' as an integer
+        */
+       case KIOCSOUND:
+       case KDMKTONE:
+#ifdef CONFIG_X86
+       case KDADDIO:
+       case KDDELIO:
+#endif
+       case KDSETMODE:
+       case KDMAPDISP:
+       case KDUNMAPDISP:
+       case KDSKBMODE:
+       case KDSKBMETA:
+       case KDSKBLED:
+       case KDSETLED:
+       case KDSIGACCEPT:
+       case VT_ACTIVATE:
+       case VT_WAITACTIVE:
+       case VT_RELDISP:
+       case VT_DISALLOCATE:
+       case VT_RESIZE:
+       case VT_RESIZEX:
+               goto fallback;
+
+       /*
+        * the rest has a compatible data structure behind arg,
+        * but we have to convert it to a proper 64 bit pointer.
+        */
+       default:
+               arg = (unsigned long)compat_ptr(arg);
+               goto fallback;
+       }
+out:
+       tty_unlock();
+       return ret;
+
+fallback:
+       tty_unlock();
+       return vt_ioctl(tty, file, cmd, arg);
+}
+
+
+#endif /* CONFIG_COMPAT */
+
+
+/*
+ * Performs the back end of a vt switch. Called under the console
+ * semaphore.
+ */
+static void complete_change_console(struct vc_data *vc)
+{
+       unsigned char old_vc_mode;
+       int old = fg_console;
+
+       last_console = fg_console;
+
+       /*
+        * If we're switching, we could be going from KD_GRAPHICS to
+        * KD_TEXT mode or vice versa, which means we need to blank or
+        * unblank the screen later.
+        */
+       old_vc_mode = vc_cons[fg_console].d->vc_mode;
+       switch_screen(vc);
+
+       /*
+        * This can't appear below a successful kill_pid().  If it did,
+        * then the *blank_screen operation could occur while X, having
+        * received acqsig, is waking up on another processor.  This
+        * condition can lead to overlapping accesses to the VGA range
+        * and the framebuffer (causing system lockups).
+        *
+        * To account for this we duplicate this code below only if the
+        * controlling process is gone and we've called reset_vc.
+        */
+       if (old_vc_mode != vc->vc_mode) {
+               if (vc->vc_mode == KD_TEXT)
+                       do_unblank_screen(1);
+               else
+                       do_blank_screen(1);
+       }
+
+       /*
+        * If this new console is under process control, send it a signal
+        * telling it that it has acquired. Also check if it has died and
+        * clean up (similar to logic employed in change_console())
+        */
+       if (vc->vt_mode.mode == VT_PROCESS) {
+               /*
+                * Send the signal as privileged - kill_pid() will
+                * tell us if the process has gone or something else
+                * is awry
+                */
+               if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) {
+               /*
+                * The controlling process has died, so we revert back to
+                * normal operation. In this case, we'll also change back
+                * to KD_TEXT mode. I'm not sure if this is strictly correct
+                * but it saves the agony when the X server dies and the screen
+                * remains blanked due to KD_GRAPHICS! It would be nice to do
+                * this outside of VT_PROCESS but there is no single process
+                * to account for and tracking tty count may be undesirable.
+                */
+                       reset_vc(vc);
+
+                       if (old_vc_mode != vc->vc_mode) {
+                               if (vc->vc_mode == KD_TEXT)
+                                       do_unblank_screen(1);
+                               else
+                                       do_blank_screen(1);
+                       }
+               }
+       }
+
+       /*
+        * Wake anyone waiting for their VT to activate
+        */
+       vt_event_post(VT_EVENT_SWITCH, old, vc->vc_num);
+       return;
+}
+
+/*
+ * Performs the front-end of a vt switch
+ */
+void change_console(struct vc_data *new_vc)
+{
+       struct vc_data *vc;
+
+       if (!new_vc || new_vc->vc_num == fg_console || vt_dont_switch)
+               return;
+
+       /*
+        * If this vt is in process mode, then we need to handshake with
+        * that process before switching. Essentially, we store where that
+        * vt wants to switch to and wait for it to tell us when it's done
+        * (via VT_RELDISP ioctl).
+        *
+        * We also check to see if the controlling process still exists.
+        * If it doesn't, we reset this vt to auto mode and continue.
+        * This is a cheap way to track process control. The worst thing
+        * that can happen is: we send a signal to a process, it dies, and
+        * the switch gets "lost" waiting for a response; hopefully, the
+        * user will try again, we'll detect the process is gone (unless
+        * the user waits just the right amount of time :-) and revert the
+        * vt to auto control.
+        */
+       vc = vc_cons[fg_console].d;
+       if (vc->vt_mode.mode == VT_PROCESS) {
+               /*
+                * Send the signal as privileged - kill_pid() will
+                * tell us if the process has gone or something else
+                * is awry.
+                *
+                * We need to set vt_newvt *before* sending the signal or we
+                * have a race.
+                */
+               vc->vt_newvt = new_vc->vc_num;
+               if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {
+                       /*
+                        * It worked. Mark the vt to switch to and
+                        * return. The process needs to send us a
+                        * VT_RELDISP ioctl to complete the switch.
+                        */
+                       return;
+               }
+
+               /*
+                * The controlling process has died, so we revert back to
+                * normal operation. In this case, we'll also change back
+                * to KD_TEXT mode. I'm not sure if this is strictly correct
+                * but it saves the agony when the X server dies and the screen
+                * remains blanked due to KD_GRAPHICS! It would be nice to do
+                * this outside of VT_PROCESS but there is no single process
+                * to account for and tracking tty count may be undesirable.
+                */
+               reset_vc(vc);
+
+               /*
+                * Fall through to normal (VT_AUTO) handling of the switch...
+                */
+       }
+
+       /*
+        * Ignore all switches in KD_GRAPHICS+VT_AUTO mode
+        */
+       if (vc->vc_mode == KD_GRAPHICS)
+               return;
+
+       complete_change_console(new_vc);
+}
+
+/* Perform a kernel triggered VT switch for suspend/resume */
+
+static int disable_vt_switch;
+
+int vt_move_to_console(unsigned int vt, int alloc)
+{
+       int prev;
+
+       acquire_console_sem();
+       /* Graphics mode - up to X */
+       if (disable_vt_switch) {
+               release_console_sem();
+               return 0;
+       }
+       prev = fg_console;
+
+       if (alloc && vc_allocate(vt)) {
+               /* we can't have a free VC for now. Too bad,
+                * we don't want to mess the screen for now. */
+               release_console_sem();
+               return -ENOSPC;
+       }
+
+       if (set_console(vt)) {
+               /*
+                * We're unable to switch to the SUSPEND_CONSOLE.
+                * Let the calling function know so it can decide
+                * what to do.
+                */
+               release_console_sem();
+               return -EIO;
+       }
+       release_console_sem();
+       tty_lock();
+       if (vt_waitactive(vt + 1)) {
+               pr_debug("Suspend: Can't switch VCs.");
+               tty_unlock();
+               return -EINTR;
+       }
+       tty_unlock();
+       return prev;
+}
+
+/*
+ * Normally during a suspend, we allocate a new console and switch to it.
+ * When we resume, we switch back to the original console.  This switch
+ * can be slow, so on systems where the framebuffer can handle restoration
+ * of video registers anyways, there's little point in doing the console
+ * switch.  This function allows you to disable it by passing it '0'.
+ */
+void pm_set_vt_switch(int do_switch)
+{
+       acquire_console_sem();
+       disable_vt_switch = !do_switch;
+       release_console_sem();
+}
+EXPORT_SYMBOL(pm_set_vt_switch);
index cb23355f52d3d8b5335dbdf1e5b07a32c77b281a..fbe86ca95802b93d68ace2718280a4aeb8b533c2 100644 (file)
@@ -811,7 +811,6 @@ int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
                INFO(dev, "MAC %pM\n", net->dev_addr);
                INFO(dev, "HOST MAC %pM\n", dev->host_mac);
 
-               netif_stop_queue(net);
                the_dev = dev;
        }
 
index 5aff46c61e521cbaef027b92d1a4bdd7bb86c547..355abcdcda980acfcd70dcb54d4bb798edf6fcae 100644 (file)
@@ -81,7 +81,7 @@ u) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for
 
 v) mount check for unmatched uids
 
-w) Add support for new vfs entry points for setlease and fallocate 
+w) Add support for new vfs entry point for fallocate
 
 x) Fix Samba 3 server to handle Linux kernel aio so dbench with lots of 
 processes can proceed better in parallel (on the server)
index 525ba59a41058a6d13f4311fb841eb2604a00140..e9a393c9c2ca4ddb8ec3d75cfcf0766234ec1789 100644 (file)
@@ -15,7 +15,7 @@
  *   the GNU Lesser General Public License for more details.
  *
  */
-#include <linux/radix-tree.h>
+#include <linux/rbtree.h>
 
 #ifndef _CIFS_FS_SB_H
 #define _CIFS_FS_SB_H
@@ -42,9 +42,9 @@
 #define CIFS_MOUNT_MULTIUSER   0x20000 /* multiuser mount */
 
 struct cifs_sb_info {
-       struct radix_tree_root tlink_tree;
-#define CIFS_TLINK_MASTER_TAG          0       /* is "master" (mount) tcon */
+       struct rb_root tlink_tree;
        spinlock_t tlink_tree_lock;
+       struct tcon_link *master_tlink;
        struct nls_table *local_nls;
        unsigned int rsize;
        unsigned int wsize;
index 75c4eaa7958821483c6829658ab6469a8ad8c152..9c3789762ab7c4c92a7d67859c34b32cb196f1ab 100644 (file)
@@ -116,7 +116,7 @@ cifs_read_super(struct super_block *sb, void *data,
                return -ENOMEM;
 
        spin_lock_init(&cifs_sb->tlink_tree_lock);
-       INIT_RADIX_TREE(&cifs_sb->tlink_tree, GFP_KERNEL);
+       cifs_sb->tlink_tree = RB_ROOT;
 
        rc = bdi_setup_and_register(&cifs_sb->bdi, "cifs", BDI_CAP_MAP_COPY);
        if (rc) {
@@ -321,8 +321,7 @@ cifs_alloc_inode(struct super_block *sb)
        /* Until the file is open and we have gotten oplock
        info back from the server, can not assume caching of
        file data or metadata */
-       cifs_inode->clientCanCacheRead = false;
-       cifs_inode->clientCanCacheAll = false;
+       cifs_set_oplock_level(cifs_inode, 0);
        cifs_inode->delete_pending = false;
        cifs_inode->invalid_mapping = false;
        cifs_inode->vfs_inode.i_blkbits = 14;  /* 2**14 = CIFS_MAX_MSGSIZE */
index f259e4d7612d5f2a50f70f6b65802b4fff01621c..b577bf0a1bb3622491ed0a885ca30b9e7684d24e 100644 (file)
@@ -336,7 +336,8 @@ struct cifsTconInfo {
  * "get" on the container.
  */
 struct tcon_link {
-       unsigned long           tl_index;
+       struct rb_node          tl_rbnode;
+       uid_t                   tl_uid;
        unsigned long           tl_flags;
 #define TCON_LINK_MASTER       0
 #define TCON_LINK_PENDING      1
index edb6d90efdf27ac2272c961c7269fbbfab2c0aa7..7ed69b6b5fe6719f66ed5af0a0b38d2cda1aa352 100644 (file)
@@ -104,6 +104,7 @@ extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
 extern u64 cifs_UnixTimeToNT(struct timespec);
 extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
                                      int offset);
+extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
 
 extern struct cifsFileInfo *cifs_new_fileinfo(__u16 fileHandle,
                                struct file *file, struct tcon_link *tlink,
index 9eb327defa1d39fc16d1c8f0837de36a65e43c92..251a17c03545dfc35e8ab37e1ea5a612e94f7536 100644 (file)
@@ -116,6 +116,7 @@ struct smb_vol {
 
 static int ipv4_connect(struct TCP_Server_Info *server);
 static int ipv6_connect(struct TCP_Server_Info *server);
+static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink);
 static void cifs_prune_tlinks(struct work_struct *work);
 
 /*
@@ -2900,24 +2901,16 @@ remote_path_check:
                goto mount_fail_check;
        }
 
-       tlink->tl_index = pSesInfo->linux_uid;
+       tlink->tl_uid = pSesInfo->linux_uid;
        tlink->tl_tcon = tcon;
        tlink->tl_time = jiffies;
        set_bit(TCON_LINK_MASTER, &tlink->tl_flags);
        set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
 
-       rc = radix_tree_preload(GFP_KERNEL);
-       if (rc == -ENOMEM) {
-               kfree(tlink);
-               goto mount_fail_check;
-       }
-
+       cifs_sb->master_tlink = tlink;
        spin_lock(&cifs_sb->tlink_tree_lock);
-       radix_tree_insert(&cifs_sb->tlink_tree, pSesInfo->linux_uid, tlink);
-       radix_tree_tag_set(&cifs_sb->tlink_tree, pSesInfo->linux_uid,
-                          CIFS_TLINK_MASTER_TAG);
+       tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
        spin_unlock(&cifs_sb->tlink_tree_lock);
-       radix_tree_preload_end();
 
        queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks,
                                TLINK_IDLE_EXPIRE);
@@ -3107,32 +3100,25 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
 int
 cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
 {
-       int i, ret;
+       struct rb_root *root = &cifs_sb->tlink_tree;
+       struct rb_node *node;
+       struct tcon_link *tlink;
        char *tmp;
-       struct tcon_link *tlink[8];
-       unsigned long index = 0;
 
        cancel_delayed_work_sync(&cifs_sb->prune_tlinks);
 
-       do {
-               spin_lock(&cifs_sb->tlink_tree_lock);
-               ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree,
-                                            (void **)tlink, index,
-                                            ARRAY_SIZE(tlink));
-               /* increment index for next pass */
-               if (ret > 0)
-                       index = tlink[ret - 1]->tl_index + 1;
-               for (i = 0; i < ret; i++) {
-                       cifs_get_tlink(tlink[i]);
-                       clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags);
-                       radix_tree_delete(&cifs_sb->tlink_tree,
-                                                       tlink[i]->tl_index);
-               }
-               spin_unlock(&cifs_sb->tlink_tree_lock);
+       spin_lock(&cifs_sb->tlink_tree_lock);
+       while ((node = rb_first(root))) {
+               tlink = rb_entry(node, struct tcon_link, tl_rbnode);
+               cifs_get_tlink(tlink);
+               clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
+               rb_erase(node, root);
 
-               for (i = 0; i < ret; i++)
-                       cifs_put_tlink(tlink[i]);
-       } while (ret != 0);
+               spin_unlock(&cifs_sb->tlink_tree_lock);
+               cifs_put_tlink(tlink);
+               spin_lock(&cifs_sb->tlink_tree_lock);
+       }
+       spin_unlock(&cifs_sb->tlink_tree_lock);
 
        tmp = cifs_sb->prepath;
        cifs_sb->prepathlen = 0;
@@ -3271,22 +3257,10 @@ out:
        return tcon;
 }
 
-static struct tcon_link *
+static inline struct tcon_link *
 cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb)
 {
-       struct tcon_link *tlink;
-       unsigned int ret;
-
-       spin_lock(&cifs_sb->tlink_tree_lock);
-       ret = radix_tree_gang_lookup_tag(&cifs_sb->tlink_tree, (void **)&tlink,
-                                       0, 1, CIFS_TLINK_MASTER_TAG);
-       spin_unlock(&cifs_sb->tlink_tree_lock);
-
-       /* the master tcon should always be present */
-       if (ret == 0)
-               BUG();
-
-       return tlink;
+       return cifs_sb->master_tlink;
 }
 
 struct cifsTconInfo *
@@ -3302,6 +3276,47 @@ cifs_sb_tcon_pending_wait(void *unused)
        return signal_pending(current) ? -ERESTARTSYS : 0;
 }
 
+/* find and return a tlink with given uid */
+static struct tcon_link *
+tlink_rb_search(struct rb_root *root, uid_t uid)
+{
+       struct rb_node *node = root->rb_node;
+       struct tcon_link *tlink;
+
+       while (node) {
+               tlink = rb_entry(node, struct tcon_link, tl_rbnode);
+
+               if (tlink->tl_uid > uid)
+                       node = node->rb_left;
+               else if (tlink->tl_uid < uid)
+                       node = node->rb_right;
+               else
+                       return tlink;
+       }
+       return NULL;
+}
+
+/* insert a tcon_link into the tree */
+static void
+tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink)
+{
+       struct rb_node **new = &(root->rb_node), *parent = NULL;
+       struct tcon_link *tlink;
+
+       while (*new) {
+               tlink = rb_entry(*new, struct tcon_link, tl_rbnode);
+               parent = *new;
+
+               if (tlink->tl_uid > new_tlink->tl_uid)
+                       new = &((*new)->rb_left);
+               else
+                       new = &((*new)->rb_right);
+       }
+
+       rb_link_node(&new_tlink->tl_rbnode, parent, new);
+       rb_insert_color(&new_tlink->tl_rbnode, root);
+}
+
 /*
  * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the
  * current task.
@@ -3309,7 +3324,7 @@ cifs_sb_tcon_pending_wait(void *unused)
  * If the superblock doesn't refer to a multiuser mount, then just return
  * the master tcon for the mount.
  *
- * First, search the radix tree for an existing tcon for this fsuid. If one
+ * First, search the rbtree for an existing tcon for this fsuid. If one
  * exists, then check to see if it's pending construction. If it is then wait
  * for construction to complete. Once it's no longer pending, check to see if
  * it failed and either return an error or retry construction, depending on
@@ -3322,14 +3337,14 @@ struct tcon_link *
 cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
 {
        int ret;
-       unsigned long fsuid = (unsigned long) current_fsuid();
+       uid_t fsuid = current_fsuid();
        struct tcon_link *tlink, *newtlink;
 
        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
                return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
 
        spin_lock(&cifs_sb->tlink_tree_lock);
-       tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid);
+       tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
        if (tlink)
                cifs_get_tlink(tlink);
        spin_unlock(&cifs_sb->tlink_tree_lock);
@@ -3338,36 +3353,24 @@ cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
                newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
                if (newtlink == NULL)
                        return ERR_PTR(-ENOMEM);
-               newtlink->tl_index = fsuid;
+               newtlink->tl_uid = fsuid;
                newtlink->tl_tcon = ERR_PTR(-EACCES);
                set_bit(TCON_LINK_PENDING, &newtlink->tl_flags);
                set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags);
                cifs_get_tlink(newtlink);
 
-               ret = radix_tree_preload(GFP_KERNEL);
-               if (ret != 0) {
-                       kfree(newtlink);
-                       return ERR_PTR(ret);
-               }
-
                spin_lock(&cifs_sb->tlink_tree_lock);
                /* was one inserted after previous search? */
-               tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid);
+               tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid);
                if (tlink) {
                        cifs_get_tlink(tlink);
                        spin_unlock(&cifs_sb->tlink_tree_lock);
-                       radix_tree_preload_end();
                        kfree(newtlink);
                        goto wait_for_construction;
                }
-               ret = radix_tree_insert(&cifs_sb->tlink_tree, fsuid, newtlink);
-               spin_unlock(&cifs_sb->tlink_tree_lock);
-               radix_tree_preload_end();
-               if (ret) {
-                       kfree(newtlink);
-                       return ERR_PTR(ret);
-               }
                tlink = newtlink;
+               tlink_rb_insert(&cifs_sb->tlink_tree, tlink);
+               spin_unlock(&cifs_sb->tlink_tree_lock);
        } else {
 wait_for_construction:
                ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING,
@@ -3413,39 +3416,39 @@ cifs_prune_tlinks(struct work_struct *work)
 {
        struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info,
                                                    prune_tlinks.work);
-       struct tcon_link *tlink[8];
-       unsigned long now = jiffies;
-       unsigned long index = 0;
-       int i, ret;
+       struct rb_root *root = &cifs_sb->tlink_tree;
+       struct rb_node *node = rb_first(root);
+       struct rb_node *tmp;
+       struct tcon_link *tlink;
 
-       do {
-               spin_lock(&cifs_sb->tlink_tree_lock);
-               ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree,
-                                            (void **)tlink, index,
-                                            ARRAY_SIZE(tlink));
-               /* increment index for next pass */
-               if (ret > 0)
-                       index = tlink[ret - 1]->tl_index + 1;
-               for (i = 0; i < ret; i++) {
-                       if (test_bit(TCON_LINK_MASTER, &tlink[i]->tl_flags) ||
-                           atomic_read(&tlink[i]->tl_count) != 0 ||
-                           time_after(tlink[i]->tl_time + TLINK_IDLE_EXPIRE,
-                                      now)) {
-                               tlink[i] = NULL;
-                               continue;
-                       }
-                       cifs_get_tlink(tlink[i]);
-                       clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags);
-                       radix_tree_delete(&cifs_sb->tlink_tree,
-                                         tlink[i]->tl_index);
-               }
-               spin_unlock(&cifs_sb->tlink_tree_lock);
+       /*
+        * Because we drop the spinlock in the loop in order to put the tlink
+        * it's not guarded against removal of links from the tree. The only
+        * places that remove entries from the tree are this function and
+        * umounts. Because this function is non-reentrant and is canceled
+        * before umount can proceed, this is safe.
+        */
+       spin_lock(&cifs_sb->tlink_tree_lock);
+       node = rb_first(root);
+       while (node != NULL) {
+               tmp = node;
+               node = rb_next(tmp);
+               tlink = rb_entry(tmp, struct tcon_link, tl_rbnode);
+
+               if (test_bit(TCON_LINK_MASTER, &tlink->tl_flags) ||
+                   atomic_read(&tlink->tl_count) != 0 ||
+                   time_after(tlink->tl_time + TLINK_IDLE_EXPIRE, jiffies))
+                       continue;
 
-               for (i = 0; i < ret; i++) {
-                       if (tlink[i] != NULL)
-                               cifs_put_tlink(tlink[i]);
-               }
-       } while (ret != 0);
+               cifs_get_tlink(tlink);
+               clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
+               rb_erase(tmp, root);
+
+               spin_unlock(&cifs_sb->tlink_tree_lock);
+               cifs_put_tlink(tlink);
+               spin_lock(&cifs_sb->tlink_tree_lock);
+       }
+       spin_unlock(&cifs_sb->tlink_tree_lock);
 
        queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks,
                                TLINK_IDLE_EXPIRE);
index ae82159cf7fa6921bb3a27a1fc5e56fbb1045a5c..06c3e83fa387fecf63b93e33a0455dac6da45f6d 100644 (file)
@@ -146,12 +146,7 @@ client_can_cache:
                rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
                                         xid, NULL);
 
-       if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
-               pCifsInode->clientCanCacheAll = true;
-               pCifsInode->clientCanCacheRead = true;
-               cFYI(1, "Exclusive Oplock granted on inode %p", inode);
-       } else if ((oplock & 0xF) == OPLOCK_READ)
-               pCifsInode->clientCanCacheRead = true;
+       cifs_set_oplock_level(pCifsInode, oplock);
 
        return rc;
 }
@@ -253,12 +248,7 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
                list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
        spin_unlock(&cifs_file_list_lock);
 
-       if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
-               pCifsInode->clientCanCacheAll = true;
-               pCifsInode->clientCanCacheRead = true;
-               cFYI(1, "Exclusive Oplock inode %p", inode);
-       } else if ((oplock & 0xF) == OPLOCK_READ)
-               pCifsInode->clientCanCacheRead = true;
+       cifs_set_oplock_level(pCifsInode, oplock);
 
        file->private_data = pCifsFile;
        return pCifsFile;
@@ -271,8 +261,9 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
  */
 void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
 {
+       struct inode *inode = cifs_file->dentry->d_inode;
        struct cifsTconInfo *tcon = tlink_tcon(cifs_file->tlink);
-       struct cifsInodeInfo *cifsi = CIFS_I(cifs_file->dentry->d_inode);
+       struct cifsInodeInfo *cifsi = CIFS_I(inode);
        struct cifsLockInfo *li, *tmp;
 
        spin_lock(&cifs_file_list_lock);
@@ -288,8 +279,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
        if (list_empty(&cifsi->openFileList)) {
                cFYI(1, "closing last open instance for inode %p",
                        cifs_file->dentry->d_inode);
-               cifsi->clientCanCacheRead = false;
-               cifsi->clientCanCacheAll  = false;
+               cifs_set_oplock_level(cifsi, 0);
        }
        spin_unlock(&cifs_file_list_lock);
 
@@ -607,8 +597,6 @@ reopen_success:
                rc = filemap_write_and_wait(inode->i_mapping);
                mapping_set_error(inode->i_mapping, rc);
 
-               pCifsInode->clientCanCacheAll = false;
-               pCifsInode->clientCanCacheRead = false;
                if (tcon->unix_ext)
                        rc = cifs_get_inode_info_unix(&inode,
                                full_path, inode->i_sb, xid);
@@ -622,18 +610,9 @@ reopen_success:
             invalidate the current end of file on the server
             we can not go to the server to get the new inod
             info */
-       if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
-               pCifsInode->clientCanCacheAll = true;
-               pCifsInode->clientCanCacheRead = true;
-               cFYI(1, "Exclusive Oplock granted on inode %p",
-                        pCifsFile->dentry->d_inode);
-       } else if ((oplock & 0xF) == OPLOCK_READ) {
-               pCifsInode->clientCanCacheRead = true;
-               pCifsInode->clientCanCacheAll = false;
-       } else {
-               pCifsInode->clientCanCacheRead = false;
-               pCifsInode->clientCanCacheAll = false;
-       }
+
+       cifs_set_oplock_level(pCifsInode, oplock);
+
        cifs_relock_file(pCifsFile);
 
 reopen_error_exit:
@@ -775,12 +754,6 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
 
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
        tcon = tlink_tcon(((struct cifsFileInfo *)file->private_data)->tlink);
-
-       if (file->private_data == NULL) {
-               rc = -EBADF;
-               FreeXid(xid);
-               return rc;
-       }
        netfid = ((struct cifsFileInfo *)file->private_data)->netfid;
 
        if ((tcon->ses->capabilities & CAP_UNIX) &&
@@ -956,6 +929,7 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
 ssize_t cifs_user_write(struct file *file, const char __user *write_data,
        size_t write_size, loff_t *poffset)
 {
+       struct inode *inode = file->f_path.dentry->d_inode;
        int rc = 0;
        unsigned int bytes_written = 0;
        unsigned int total_written;
@@ -963,7 +937,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
        struct cifsTconInfo *pTcon;
        int xid, long_op;
        struct cifsFileInfo *open_file;
-       struct cifsInodeInfo *cifsi = CIFS_I(file->f_path.dentry->d_inode);
+       struct cifsInodeInfo *cifsi = CIFS_I(inode);
 
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
 
@@ -1029,21 +1003,17 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
 
        cifs_stats_bytes_written(pTcon, total_written);
 
-       /* since the write may have blocked check these pointers again */
-       if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
-               struct inode *inode = file->f_path.dentry->d_inode;
 /* Do not update local mtime - server will set its actual value on write
- *             inode->i_ctime = inode->i_mtime =
- *                     current_fs_time(inode->i_sb);*/
-               if (total_written > 0) {
-                       spin_lock(&inode->i_lock);
-                       if (*poffset > file->f_path.dentry->d_inode->i_size)
-                               i_size_write(file->f_path.dentry->d_inode,
-                                       *poffset);
-                       spin_unlock(&inode->i_lock);
-               }
-               mark_inode_dirty_sync(file->f_path.dentry->d_inode);
+ *     inode->i_ctime = inode->i_mtime =
+ *             current_fs_time(inode->i_sb);*/
+       if (total_written > 0) {
+               spin_lock(&inode->i_lock);
+               if (*poffset > inode->i_size)
+                       i_size_write(inode, *poffset);
+               spin_unlock(&inode->i_lock);
        }
+       mark_inode_dirty_sync(inode);
+
        FreeXid(xid);
        return total_written;
 }
@@ -1178,7 +1148,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
                                        bool fsuid_only)
 {
        struct cifsFileInfo *open_file;
-       struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
+       struct cifs_sb_info *cifs_sb;
        bool any_available = false;
        int rc;
 
@@ -1192,6 +1162,8 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
                return NULL;
        }
 
+       cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
+
        /* only filter by fsuid on multiuser mounts */
        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
                fsuid_only = false;
index 077bf756f34231300c6b0d7fdae7cedf6023bd08..2fa22f20cfc500060991205e115995d2aa0253f3 100644 (file)
@@ -63,8 +63,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
 #ifdef CONFIG_CIFS_POSIX
                case FS_IOC_GETFLAGS:
                        if (CIFS_UNIX_EXTATTR_CAP & caps) {
-                               if (pSMBFile == NULL)
-                                       break;
                                rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
                                        &ExtAttrBits, &ExtAttrMask);
                                if (rc == 0)
@@ -80,8 +78,6 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
                                        rc = -EFAULT;
                                        break;
                                }
-                               if (pSMBFile == NULL)
-                                       break;
                                /* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid,
                                        extAttrBits, &ExtAttrMask);*/
                        }
index c4e296fe351876252a48210f81f6cbae165562f8..43f10281bc19e80be48303e1bd9c974b4882cb37 100644 (file)
@@ -569,10 +569,9 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
 
                                cFYI(1, "file id match, oplock break");
                                pCifsInode = CIFS_I(netfile->dentry->d_inode);
-                               pCifsInode->clientCanCacheAll = false;
-                               if (pSMB->OplockLevel == 0)
-                                       pCifsInode->clientCanCacheRead = false;
 
+                               cifs_set_oplock_level(pCifsInode,
+                                                     pSMB->OplockLevel);
                                /*
                                 * cifs_oplock_break_put() can't be called
                                 * from here.  Get reference after queueing
@@ -722,3 +721,23 @@ cifs_autodisable_serverino(struct cifs_sb_info *cifs_sb)
                           cifs_sb_master_tcon(cifs_sb)->treeName);
        }
 }
+
+void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
+{
+       oplock &= 0xF;
+
+       if (oplock == OPLOCK_EXCLUSIVE) {
+               cinode->clientCanCacheAll = true;
+               cinode->clientCanCacheRead = true;
+               cFYI(1, "Exclusive Oplock granted on inode %p",
+                    &cinode->vfs_inode);
+       } else if (oplock == OPLOCK_READ) {
+               cinode->clientCanCacheAll = false;
+               cinode->clientCanCacheRead = true;
+               cFYI(1, "Level II Oplock granted on inode %p",
+                   &cinode->vfs_inode);
+       } else {
+               cinode->clientCanCacheAll = false;
+               cinode->clientCanCacheRead = false;
+       }
+}
index 8b5dd6369f82c19d5ba28dea07018e4fb13a025f..6a5edea2d70b3ac7c56e8b272686b5a799eabbcf 100644 (file)
@@ -177,7 +177,7 @@ struct mpage_da_data {
 
 struct ext4_io_page {
        struct page     *p_page;
-       int             p_count;
+       atomic_t        p_count;
 };
 
 #define MAX_IO_PAGES 128
@@ -858,6 +858,7 @@ struct ext4_inode_info {
        spinlock_t i_completed_io_lock;
        /* current io_end structure for async DIO write*/
        ext4_io_end_t *cur_aio_dio;
+       atomic_t i_ioend_count; /* Number of outstanding io_end structs */
 
        /*
         * Transactions that contain inode's metadata needed to complete
@@ -2060,6 +2061,7 @@ extern int ext4_move_extents(struct file *o_filp, struct file *d_filp,
 /* page-io.c */
 extern int __init ext4_init_pageio(void);
 extern void ext4_exit_pageio(void);
+extern void ext4_ioend_wait(struct inode *);
 extern void ext4_free_io_end(ext4_io_end_t *io);
 extern ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags);
 extern int ext4_end_io_nolock(ext4_io_end_t *io);
index 4d78342f3bf07ec61dbe8346eef88706aa5abebb..bdbe69902207c151df025d98690c4c016cf0b0e9 100644 (file)
@@ -53,6 +53,7 @@
 static inline int ext4_begin_ordered_truncate(struct inode *inode,
                                              loff_t new_size)
 {
+       trace_ext4_begin_ordered_truncate(inode, new_size);
        return jbd2_journal_begin_ordered_truncate(
                                        EXT4_SB(inode->i_sb)->s_journal,
                                        &EXT4_I(inode)->jinode,
@@ -178,6 +179,7 @@ void ext4_evict_inode(struct inode *inode)
        handle_t *handle;
        int err;
 
+       trace_ext4_evict_inode(inode);
        if (inode->i_nlink) {
                truncate_inode_pages(&inode->i_data, 0);
                goto no_delete;
@@ -5647,6 +5649,7 @@ int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
        int err, ret;
 
        might_sleep();
+       trace_ext4_mark_inode_dirty(inode, _RET_IP_);
        err = ext4_reserve_inode_write(handle, inode, &iloc);
        if (ext4_handle_valid(handle) &&
            EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize &&
index c58eba34724a4281f1cb8bb405ab607ef09b49ff..5b4d4e3a4d58e3506c15e891e7b8df394bc0838f 100644 (file)
@@ -4640,8 +4640,6 @@ do_more:
                 * with group lock held. generate_buddy look at
                 * them with group lock_held
                 */
-               if (test_opt(sb, DISCARD))
-                       ext4_issue_discard(sb, block_group, bit, count);
                ext4_lock_group(sb, block_group);
                mb_clear_bits(bitmap_bh->b_data, bit, count);
                mb_free_blocks(inode, &e4b, bit, count);
index 46a7d6a9d9764b82075071c94f661cc65c3675fc..7f5451cd1d38bff2399471750618fc7429ce5c5e 100644 (file)
 
 static struct kmem_cache *io_page_cachep, *io_end_cachep;
 
+#define WQ_HASH_SZ             37
+#define to_ioend_wq(v) (&ioend_wq[((unsigned long)v) % WQ_HASH_SZ])
+static wait_queue_head_t ioend_wq[WQ_HASH_SZ];
+
 int __init ext4_init_pageio(void)
 {
+       int i;
+
        io_page_cachep = KMEM_CACHE(ext4_io_page, SLAB_RECLAIM_ACCOUNT);
        if (io_page_cachep == NULL)
                return -ENOMEM;
@@ -42,6 +48,8 @@ int __init ext4_init_pageio(void)
                kmem_cache_destroy(io_page_cachep);
                return -ENOMEM;
        }
+       for (i = 0; i < WQ_HASH_SZ; i++)
+               init_waitqueue_head(&ioend_wq[i]);
 
        return 0;
 }
@@ -52,24 +60,37 @@ void ext4_exit_pageio(void)
        kmem_cache_destroy(io_page_cachep);
 }
 
+void ext4_ioend_wait(struct inode *inode)
+{
+       wait_queue_head_t *wq = to_ioend_wq(inode);
+
+       wait_event(*wq, (atomic_read(&EXT4_I(inode)->i_ioend_count) == 0));
+}
+
+static void put_io_page(struct ext4_io_page *io_page)
+{
+       if (atomic_dec_and_test(&io_page->p_count)) {
+               end_page_writeback(io_page->p_page);
+               put_page(io_page->p_page);
+               kmem_cache_free(io_page_cachep, io_page);
+       }
+}
+
 void ext4_free_io_end(ext4_io_end_t *io)
 {
        int i;
+       wait_queue_head_t *wq;
 
        BUG_ON(!io);
        if (io->page)
                put_page(io->page);
-       for (i = 0; i < io->num_io_pages; i++) {
-               if (--io->pages[i]->p_count == 0) {
-                       struct page *page = io->pages[i]->p_page;
-
-                       end_page_writeback(page);
-                       put_page(page);
-                       kmem_cache_free(io_page_cachep, io->pages[i]);
-               }
-       }
+       for (i = 0; i < io->num_io_pages; i++)
+               put_io_page(io->pages[i]);
        io->num_io_pages = 0;
-       iput(io->inode);
+       wq = to_ioend_wq(io->inode);
+       if (atomic_dec_and_test(&EXT4_I(io->inode)->i_ioend_count) &&
+           waitqueue_active(wq))
+               wake_up_all(wq);
        kmem_cache_free(io_end_cachep, io);
 }
 
@@ -142,8 +163,8 @@ ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags)
        io = kmem_cache_alloc(io_end_cachep, flags);
        if (io) {
                memset(io, 0, sizeof(*io));
-               io->inode = igrab(inode);
-               BUG_ON(!io->inode);
+               atomic_inc(&EXT4_I(inode)->i_ioend_count);
+               io->inode = inode;
                INIT_WORK(&io->work, ext4_end_io_work);
                INIT_LIST_HEAD(&io->list);
        }
@@ -171,35 +192,15 @@ static void ext4_end_bio(struct bio *bio, int error)
        struct workqueue_struct *wq;
        struct inode *inode;
        unsigned long flags;
-       ext4_fsblk_t err_block;
        int i;
 
        BUG_ON(!io_end);
-       inode = io_end->inode;
        bio->bi_private = NULL;
        bio->bi_end_io = NULL;
        if (test_bit(BIO_UPTODATE, &bio->bi_flags))
                error = 0;
-       err_block = bio->bi_sector >> (inode->i_blkbits - 9);
        bio_put(bio);
 
-       if (!(inode->i_sb->s_flags & MS_ACTIVE)) {
-               pr_err("sb umounted, discard end_io request for inode %lu\n",
-                       io_end->inode->i_ino);
-               ext4_free_io_end(io_end);
-               return;
-       }
-
-       if (error) {
-               io_end->flag |= EXT4_IO_END_ERROR;
-               ext4_warning(inode->i_sb, "I/O error writing to inode %lu "
-                            "(offset %llu size %ld starting block %llu)",
-                            inode->i_ino,
-                            (unsigned long long) io_end->offset,
-                            (long) io_end->size,
-                            (unsigned long long) err_block);
-       }
-
        for (i = 0; i < io_end->num_io_pages; i++) {
                struct page *page = io_end->pages[i]->p_page;
                struct buffer_head *bh, *head;
@@ -236,13 +237,7 @@ static void ext4_end_bio(struct bio *bio, int error)
                        } while (bh != head);
                }
 
-               if (--io_end->pages[i]->p_count == 0) {
-                       struct page *page = io_end->pages[i]->p_page;
-
-                       end_page_writeback(page);
-                       put_page(page);
-                       kmem_cache_free(io_page_cachep, io_end->pages[i]);
-               }
+               put_io_page(io_end->pages[i]);
 
                /*
                 * If this is a partial write which happened to make
@@ -254,8 +249,19 @@ static void ext4_end_bio(struct bio *bio, int error)
                if (!partial_write)
                        SetPageUptodate(page);
        }
-
        io_end->num_io_pages = 0;
+       inode = io_end->inode;
+
+       if (error) {
+               io_end->flag |= EXT4_IO_END_ERROR;
+               ext4_warning(inode->i_sb, "I/O error writing to inode %lu "
+                            "(offset %llu size %ld starting block %llu)",
+                            inode->i_ino,
+                            (unsigned long long) io_end->offset,
+                            (long) io_end->size,
+                            (unsigned long long)
+                            bio->bi_sector >> (inode->i_blkbits - 9));
+       }
 
        /* Add the io_end to per-inode completed io list*/
        spin_lock_irqsave(&EXT4_I(inode)->i_completed_io_lock, flags);
@@ -305,7 +311,6 @@ static int io_submit_init(struct ext4_io_submit *io,
        bio->bi_private = io->io_end = io_end;
        bio->bi_end_io = ext4_end_bio;
 
-       io_end->inode = inode;
        io_end->offset = (page->index << PAGE_CACHE_SHIFT) + bh_offset(bh);
 
        io->io_bio = bio;
@@ -360,7 +365,7 @@ submit_and_retry:
        if ((io_end->num_io_pages == 0) ||
            (io_end->pages[io_end->num_io_pages-1] != io_page)) {
                io_end->pages[io_end->num_io_pages++] = io_page;
-               io_page->p_count++;
+               atomic_inc(&io_page->p_count);
        }
        return 0;
 }
@@ -389,7 +394,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
                return -ENOMEM;
        }
        io_page->p_page = page;
-       io_page->p_count = 0;
+       atomic_set(&io_page->p_count, 1);
        get_page(page);
 
        for (bh = head = page_buffers(page), block_start = 0;
@@ -421,10 +426,6 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
         * PageWriteback bit from the page to prevent the system from
         * wedging later on.
         */
-       if (io_page->p_count == 0) {
-               put_page(page);
-               end_page_writeback(page);
-               kmem_cache_free(io_page_cachep, io_page);
-       }
+       put_io_page(io_page);
        return ret;
 }
index 40131b777af66c3112bb1df16265faadac435d0f..61182fe6254e94ad606a6c67fed1b30ef289ad38 100644 (file)
@@ -828,12 +828,22 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
        ei->cur_aio_dio = NULL;
        ei->i_sync_tid = 0;
        ei->i_datasync_tid = 0;
+       atomic_set(&ei->i_ioend_count, 0);
 
        return &ei->vfs_inode;
 }
 
+static int ext4_drop_inode(struct inode *inode)
+{
+       int drop = generic_drop_inode(inode);
+
+       trace_ext4_drop_inode(inode, drop);
+       return drop;
+}
+
 static void ext4_destroy_inode(struct inode *inode)
 {
+       ext4_ioend_wait(inode);
        if (!list_empty(&(EXT4_I(inode)->i_orphan))) {
                ext4_msg(inode->i_sb, KERN_ERR,
                         "Inode %lu (%p): orphan list check failed!",
@@ -1173,6 +1183,7 @@ static const struct super_operations ext4_sops = {
        .destroy_inode  = ext4_destroy_inode,
        .write_inode    = ext4_write_inode,
        .dirty_inode    = ext4_dirty_inode,
+       .drop_inode     = ext4_drop_inode,
        .evict_inode    = ext4_evict_inode,
        .put_super      = ext4_put_super,
        .sync_fs        = ext4_sync_fs,
@@ -1194,6 +1205,7 @@ static const struct super_operations ext4_nojournal_sops = {
        .destroy_inode  = ext4_destroy_inode,
        .write_inode    = ext4_write_inode,
        .dirty_inode    = ext4_dirty_inode,
+       .drop_inode     = ext4_drop_inode,
        .evict_inode    = ext4_evict_inode,
        .write_super    = ext4_write_super,
        .put_super      = ext4_put_super,
@@ -2699,7 +2711,6 @@ static int ext4_lazyinit_thread(void *arg)
        struct ext4_li_request *elr;
        unsigned long next_wakeup;
        DEFINE_WAIT(wait);
-       int ret;
 
        BUG_ON(NULL == eli);
 
@@ -2723,13 +2734,12 @@ cont_thread:
                        elr = list_entry(pos, struct ext4_li_request,
                                         lr_request);
 
-                       if (time_after_eq(jiffies, elr->lr_next_sched))
-                               ret = ext4_run_li_request(elr);
-
-                       if (ret) {
-                               ret = 0;
-                               ext4_remove_li_request(elr);
-                               continue;
+                       if (time_after_eq(jiffies, elr->lr_next_sched)) {
+                               if (ext4_run_li_request(elr) != 0) {
+                                       /* error, remove the lazy_init job */
+                                       ext4_remove_li_request(elr);
+                                       continue;
+                               }
                        }
 
                        if (time_before(elr->lr_next_sched, next_wakeup))
@@ -2740,7 +2750,8 @@ cont_thread:
                if (freezing(current))
                        refrigerator();
 
-               if (time_after_eq(jiffies, next_wakeup)) {
+               if ((time_after_eq(jiffies, next_wakeup)) ||
+                   (MAX_JIFFY_OFFSET == next_wakeup)) {
                        cond_resched();
                        continue;
                }
@@ -3348,6 +3359,24 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        get_random_bytes(&sbi->s_next_generation, sizeof(u32));
        spin_lock_init(&sbi->s_next_gen_lock);
 
+       err = percpu_counter_init(&sbi->s_freeblocks_counter,
+                       ext4_count_free_blocks(sb));
+       if (!err) {
+               err = percpu_counter_init(&sbi->s_freeinodes_counter,
+                               ext4_count_free_inodes(sb));
+       }
+       if (!err) {
+               err = percpu_counter_init(&sbi->s_dirs_counter,
+                               ext4_count_dirs(sb));
+       }
+       if (!err) {
+               err = percpu_counter_init(&sbi->s_dirtyblocks_counter, 0);
+       }
+       if (err) {
+               ext4_msg(sb, KERN_ERR, "insufficient memory");
+               goto failed_mount3;
+       }
+
        sbi->s_stripe = ext4_get_stripe_size(sbi);
        sbi->s_max_writeback_mb_bump = 128;
 
@@ -3446,22 +3475,19 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        }
        set_task_ioprio(sbi->s_journal->j_task, journal_ioprio);
 
-no_journal:
-       err = percpu_counter_init(&sbi->s_freeblocks_counter,
-                                 ext4_count_free_blocks(sb));
-       if (!err)
-               err = percpu_counter_init(&sbi->s_freeinodes_counter,
-                                         ext4_count_free_inodes(sb));
-       if (!err)
-               err = percpu_counter_init(&sbi->s_dirs_counter,
-                                         ext4_count_dirs(sb));
-       if (!err)
-               err = percpu_counter_init(&sbi->s_dirtyblocks_counter, 0);
-       if (err) {
-               ext4_msg(sb, KERN_ERR, "insufficient memory");
-               goto failed_mount_wq;
-       }
+       /*
+        * The journal may have updated the bg summary counts, so we
+        * need to update the global counters.
+        */
+       percpu_counter_set(&sbi->s_freeblocks_counter,
+                          ext4_count_free_blocks(sb));
+       percpu_counter_set(&sbi->s_freeinodes_counter,
+                          ext4_count_free_inodes(sb));
+       percpu_counter_set(&sbi->s_dirs_counter,
+                          ext4_count_dirs(sb));
+       percpu_counter_set(&sbi->s_dirtyblocks_counter, 0);
 
+no_journal:
        EXT4_SB(sb)->dio_unwritten_wq = create_workqueue("ext4-dio-unwritten");
        if (!EXT4_SB(sb)->dio_unwritten_wq) {
                printk(KERN_ERR "EXT4-fs: failed to create DIO workqueue\n");
@@ -3611,10 +3637,6 @@ failed_mount_wq:
                jbd2_journal_destroy(sbi->s_journal);
                sbi->s_journal = NULL;
        }
-       percpu_counter_destroy(&sbi->s_freeblocks_counter);
-       percpu_counter_destroy(&sbi->s_freeinodes_counter);
-       percpu_counter_destroy(&sbi->s_dirs_counter);
-       percpu_counter_destroy(&sbi->s_dirtyblocks_counter);
 failed_mount3:
        if (sbi->s_flex_groups) {
                if (is_vmalloc_addr(sbi->s_flex_groups))
@@ -3622,6 +3644,10 @@ failed_mount3:
                else
                        kfree(sbi->s_flex_groups);
        }
+       percpu_counter_destroy(&sbi->s_freeblocks_counter);
+       percpu_counter_destroy(&sbi->s_freeinodes_counter);
+       percpu_counter_destroy(&sbi->s_dirs_counter);
+       percpu_counter_destroy(&sbi->s_dirtyblocks_counter);
 failed_mount2:
        for (i = 0; i < db_count; i++)
                brelse(sbi->s_group_desc[i]);
@@ -3949,13 +3975,11 @@ static int ext4_commit_super(struct super_block *sb, int sync)
        else
                es->s_kbytes_written =
                        cpu_to_le64(EXT4_SB(sb)->s_kbytes_written);
-       if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeblocks_counter))
-               ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
-                                       &EXT4_SB(sb)->s_freeblocks_counter));
-       if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeinodes_counter))
-               es->s_free_inodes_count =
-                       cpu_to_le32(percpu_counter_sum_positive(
-                                       &EXT4_SB(sb)->s_freeinodes_counter));
+       ext4_free_blocks_count_set(es, percpu_counter_sum_positive(
+                                          &EXT4_SB(sb)->s_freeblocks_counter));
+       es->s_free_inodes_count =
+               cpu_to_le32(percpu_counter_sum_positive(
+                               &EXT4_SB(sb)->s_freeinodes_counter));
        sb->s_dirt = 0;
        BUFFER_TRACE(sbh, "marking dirty");
        mark_buffer_dirty(sbh);
@@ -4556,12 +4580,10 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
 
 static int ext4_quota_off(struct super_block *sb, int type)
 {
-       /* Force all delayed allocation blocks to be allocated */
-       if (test_opt(sb, DELALLOC)) {
-               down_read(&sb->s_umount);
+       /* Force all delayed allocation blocks to be allocated.
+        * Caller already holds s_umount sem */
+       if (test_opt(sb, DELALLOC))
                sync_filesystem(sb);
-               up_read(&sb->s_umount);
-       }
 
        return dquot_quota_off(sb, type);
 }
index 47e64170305d8f862e2f67d73420eb3e0a8ed9e4..bd8cad21998e0e41ac88435b55ae9f3d275c0283 100644 (file)
@@ -33,18 +33,18 @@ struct stat {
        int             st_blksize;     /* Optimal block size for I/O.  */
        int             __pad2;
        long            st_blocks;      /* Number 512-byte blocks allocated. */
-       int             st_atime;       /* Time of last access.  */
-       unsigned int    st_atime_nsec;
-       int             st_mtime;       /* Time of last modification.  */
-       unsigned int    st_mtime_nsec;
-       int             st_ctime;       /* Time of last status change.  */
-       unsigned int    st_ctime_nsec;
+       long            st_atime;       /* Time of last access.  */
+       unsigned long   st_atime_nsec;
+       long            st_mtime;       /* Time of last modification.  */
+       unsigned long   st_mtime_nsec;
+       long            st_ctime;       /* Time of last status change.  */
+       unsigned long   st_ctime_nsec;
        unsigned int    __unused4;
        unsigned int    __unused5;
 };
 
-#if __BITS_PER_LONG != 64
 /* This matches struct stat64 in glibc2.1. Only used for 32 bit. */
+#if __BITS_PER_LONG != 64 || defined(__ARCH_WANT_STAT64)
 struct stat64 {
        unsigned long long st_dev;      /* Device.  */
        unsigned long long st_ino;      /* File serial number.  */
index d19e2114fd867782dc8a71b7b12367a9eff561ad..5c99da1078aa2e2906e0cc8f06428c231f76970a 100644 (file)
@@ -59,19 +59,19 @@ struct sh_mmcif_plat_data {
 #define MMCIF_CE_HOST_STS2     0x0000004C
 #define MMCIF_CE_VERSION       0x0000007C
 
-extern inline u32 sh_mmcif_readl(void __iomem *addr, int reg)
+static inline u32 sh_mmcif_readl(void __iomem *addr, int reg)
 {
        return readl(addr + reg);
 }
 
-extern inline void sh_mmcif_writel(void __iomem *addr, int reg, u32 val)
+static inline void sh_mmcif_writel(void __iomem *addr, int reg, u32 val)
 {
        writel(val, addr + reg);
 }
 
 #define SH_MMCIF_BBS 512 /* boot block size */
 
-extern inline void sh_mmcif_boot_cmd_send(void __iomem *base,
+static inline void sh_mmcif_boot_cmd_send(void __iomem *base,
                                          unsigned long cmd, unsigned long arg)
 {
        sh_mmcif_writel(base, MMCIF_CE_INT, 0);
@@ -79,7 +79,7 @@ extern inline void sh_mmcif_boot_cmd_send(void __iomem *base,
        sh_mmcif_writel(base, MMCIF_CE_CMD_SET, cmd);
 }
 
-extern inline int sh_mmcif_boot_cmd_poll(void __iomem *base, unsigned long mask)
+static inline int sh_mmcif_boot_cmd_poll(void __iomem *base, unsigned long mask)
 {
        unsigned long tmp;
        int cnt;
@@ -95,14 +95,14 @@ extern inline int sh_mmcif_boot_cmd_poll(void __iomem *base, unsigned long mask)
        return -1;
 }
 
-extern inline int sh_mmcif_boot_cmd(void __iomem *base,
+static inline int sh_mmcif_boot_cmd(void __iomem *base,
                                    unsigned long cmd, unsigned long arg)
 {
        sh_mmcif_boot_cmd_send(base, cmd, arg);
        return sh_mmcif_boot_cmd_poll(base, 0x00010000);
 }
 
-extern inline int sh_mmcif_boot_do_read_single(void __iomem *base,
+static inline int sh_mmcif_boot_do_read_single(void __iomem *base,
                                               unsigned int block_nr,
                                               unsigned long *buf)
 {
@@ -125,7 +125,7 @@ extern inline int sh_mmcif_boot_do_read_single(void __iomem *base,
        return 0;
 }
 
-extern inline int sh_mmcif_boot_do_read(void __iomem *base,
+static inline int sh_mmcif_boot_do_read(void __iomem *base,
                                        unsigned long first_block,
                                        unsigned long nr_blocks,
                                        void *buf)
@@ -143,7 +143,7 @@ extern inline int sh_mmcif_boot_do_read(void __iomem *base,
        return ret;
 }
 
-extern inline void sh_mmcif_boot_init(void __iomem *base)
+static inline void sh_mmcif_boot_init(void __iomem *base)
 {
        unsigned long tmp;
 
@@ -177,7 +177,7 @@ extern inline void sh_mmcif_boot_init(void __iomem *base)
        sh_mmcif_boot_cmd(base, 0x03400040, 0x00010000);
 }
 
-extern inline void sh_mmcif_boot_slurp(void __iomem *base,
+static inline void sh_mmcif_boot_slurp(void __iomem *base,
                                       unsigned char *buf,
                                       unsigned long no_bytes)
 {
index 4dca992f3093771993ac9d98d1233df5e2f33cfa..cea0c38e7a63dfad2544043c49fca25aea9a7563 100644 (file)
@@ -122,6 +122,10 @@ int clk_rate_table_find(struct clk *clk,
 long clk_rate_div_range_round(struct clk *clk, unsigned int div_min,
                              unsigned int div_max, unsigned long rate);
 
+long clk_round_parent(struct clk *clk, unsigned long target,
+                     unsigned long *best_freq, unsigned long *parent_freq,
+                     unsigned int div_min, unsigned int div_max);
+
 #define SH_CLK_MSTP32(_parent, _enable_reg, _enable_bit, _flags)       \
 {                                                                      \
        .parent         = _parent,                                      \
index 864bd56bd3b0ba08a84958ff5d06e647d643e208..4d9dcd1383150088f598f0d0d58f7d51e7400046 100644 (file)
@@ -5,7 +5,6 @@ struct sh_timer_config {
        char *name;
        long channel_offset;
        int timer_bit;
-       char *clk;
        unsigned long clockevent_rating;
        unsigned long clocksource_rating;
 };
index 6da573c75d54cfdde09f449f6cd3dd617c49fa20..8eff83b95366049b6f55d9efd268952453329227 100644 (file)
@@ -28,7 +28,7 @@ struct caif_param {
  * @sockaddr:          Socket address to connect.
  * @priority:          Priority of the connection.
  * @link_selector:     Link selector (high bandwidth or low latency)
- * @link_name:         Name of the CAIF Link Layer to use.
+ * @ifindex:           kernel index of the interface.
  * @param:             Connect Request parameters (CAIF_SO_REQ_PARAM).
  *
  * This struct is used when connecting a CAIF channel.
@@ -39,7 +39,7 @@ struct caif_connect_request {
        struct sockaddr_caif sockaddr;
        enum caif_channel_priority priority;
        enum caif_link_selector link_selector;
-       char link_name[16];
+       int ifindex;
        struct caif_param param;
 };
 
index ce4570dff020720c2ca6d5e22a0202a78c5c42c5..87c3d11b8e555ff2ebd9a07f504cd8ab2b5fcebd 100644 (file)
@@ -121,6 +121,8 @@ struct cfspi {
        wait_queue_head_t wait;
        spinlock_t lock;
        bool flow_stop;
+       bool slave;
+       bool slave_talked;
 #ifdef CONFIG_DEBUG_FS
        enum cfspi_state dbg_state;
        u16 pcmd;
index bd646faffa47bd8cd46ed4f15e1988c7bfac8247..f688478bfb84a4afc62039e57e212978ab24929b 100644 (file)
@@ -139,10 +139,10 @@ struct dev_info *cfcnfg_get_phyid(struct cfcnfg *cnfg,
                     enum cfcnfg_phy_preference phy_pref);
 
 /**
- * cfcnfg_get_named() - Get the Physical Identifier of CAIF Link Layer
+ * cfcnfg_get_id_from_ifi() - Get the Physical Identifier of ifindex,
+ *                     it matches caif physical id with the kernel interface id.
  * @cnfg:      Configuration object
- * @name:      Name of the Physical Layer (Caif Link Layer)
+ * @ifi:       ifindex obtained from socket.c bindtodevice.
  */
-int cfcnfg_get_named(struct cfcnfg *cnfg, char *name);
-
+int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi);
 #endif                         /* CFCNFG_H_ */
index f3b201d335b3532858c846a8aadb1672de80dce3..9801c55de5d64e5357006f9cfb129bce139572dd 100644 (file)
@@ -384,7 +384,7 @@ static inline int nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen,
  *
  * Returns the first attribute which matches the specified type.
  */
-static inline struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh,
+static inline struct nlattr *nlmsg_find_attr(const struct nlmsghdr *nlh,
                                             int hdrlen, int attrtype)
 {
        return nla_find(nlmsg_attrdata(nlh, hdrlen),
index 289010d3270bfa99191cfbdfa95a02564b6638bf..e5e345fb2a5c37db45de06bcdf02f3796aec64c4 100644 (file)
@@ -98,6 +98,103 @@ TRACE_EVENT(ext4_allocate_inode,
                  (unsigned long) __entry->dir, __entry->mode)
 );
 
+TRACE_EVENT(ext4_evict_inode,
+       TP_PROTO(struct inode *inode),
+
+       TP_ARGS(inode),
+
+       TP_STRUCT__entry(
+               __field(        int,   dev_major                )
+               __field(        int,   dev_minor                )
+               __field(        ino_t,  ino                     )
+               __field(        int,    nlink                   )
+       ),
+
+       TP_fast_assign(
+               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->ino    = inode->i_ino;
+               __entry->nlink  = inode->i_nlink;
+       ),
+
+       TP_printk("dev %d,%d ino %lu nlink %d",
+                 __entry->dev_major, __entry->dev_minor,
+                 (unsigned long) __entry->ino, __entry->nlink)
+);
+
+TRACE_EVENT(ext4_drop_inode,
+       TP_PROTO(struct inode *inode, int drop),
+
+       TP_ARGS(inode, drop),
+
+       TP_STRUCT__entry(
+               __field(        int,    dev_major               )
+               __field(        int,    dev_minor               )
+               __field(        ino_t,  ino                     )
+               __field(        int,    drop                    )
+       ),
+
+       TP_fast_assign(
+               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->ino    = inode->i_ino;
+               __entry->drop   = drop;
+       ),
+
+       TP_printk("dev %d,%d ino %lu drop %d",
+                 __entry->dev_major, __entry->dev_minor,
+                 (unsigned long) __entry->ino, __entry->drop)
+);
+
+TRACE_EVENT(ext4_mark_inode_dirty,
+       TP_PROTO(struct inode *inode, unsigned long IP),
+
+       TP_ARGS(inode, IP),
+
+       TP_STRUCT__entry(
+               __field(        int,    dev_major               )
+               __field(        int,    dev_minor               )
+               __field(        ino_t,  ino                     )
+               __field(unsigned long,  ip                      )
+       ),
+
+       TP_fast_assign(
+               __entry->dev_major = MAJOR(inode->i_sb->s_dev);
+               __entry->dev_minor = MINOR(inode->i_sb->s_dev);
+               __entry->ino    = inode->i_ino;
+               __entry->ip     = IP;
+       ),
+
+       TP_printk("dev %d,%d ino %lu caller %pF",
+                 __entry->dev_major, __entry->dev_minor,
+                 (unsigned long) __entry->ino, (void *)__entry->ip)
+);
+
+TRACE_EVENT(ext4_begin_ordered_truncate,
+       TP_PROTO(struct inode *inode, loff_t new_size),
+
+       TP_ARGS(inode, new_size),
+
+       TP_STRUCT__entry(
+               __field(        int,    dev_major               )
+               __field(        int,    dev_minor               )
+               __field(        ino_t,  ino                     )
+               __field(        loff_t, new_size                )
+       ),
+
+       TP_fast_assign(
+               __entry->dev_major      = MAJOR(inode->i_sb->s_dev);
+               __entry->dev_minor      = MINOR(inode->i_sb->s_dev);
+               __entry->ino            = inode->i_ino;
+               __entry->new_size       = new_size;
+       ),
+
+       TP_printk("dev %d,%d ino %lu new_size %lld",
+                 __entry->dev_major, __entry->dev_minor,
+                 (unsigned long) __entry->ino,
+                 (long long) __entry->new_size)
+);
+
 DECLARE_EVENT_CLASS(ext4__write_begin,
 
        TP_PROTO(struct inode *inode, loff_t pos, unsigned int len,
index b194febf5799bab766e5aef261e566902a086b28..21aa7b3001fb49edce43446dd85898f62ab33d98 100644 (file)
@@ -95,6 +95,14 @@ static void __exit_signal(struct task_struct *tsk)
                tty = sig->tty;
                sig->tty = NULL;
        } else {
+               /*
+                * This can only happen if the caller is de_thread().
+                * FIXME: this is the temporary hack, we should teach
+                * posix-cpu-timers to handle this case correctly.
+                */
+               if (unlikely(has_group_leader_pid(tsk)))
+                       posix_cpu_timers_exit_group(tsk);
+
                /*
                 * If there is any task waiting for the group exit
                 * then notify it:
index c7cf397fb92958bbcbd2772e13a8d4a4d9c00b6d..859ea5a9605fa40fe47aedcb865ab08c66a43797 100644 (file)
@@ -70,17 +70,10 @@ static const struct vm_operations_struct relay_file_mmap_ops = {
  */
 static struct page **relay_alloc_page_array(unsigned int n_pages)
 {
-       struct page **array;
-       size_t pa_size = n_pages * sizeof(struct page *);
-
-       if (pa_size > PAGE_SIZE) {
-               array = vmalloc(pa_size);
-               if (array)
-                       memset(array, 0, pa_size);
-       } else {
-               array = kzalloc(pa_size, GFP_KERNEL);
-       }
-       return array;
+       const size_t pa_size = n_pages * sizeof(struct page *);
+       if (pa_size > PAGE_SIZE)
+               return vzalloc(pa_size);
+       return kzalloc(pa_size, GFP_KERNEL);
 }
 
 /*
index bafba687a6d849a11f0201acd3d7ae5e63e9301e..6e3c41a4024c1cc66be01218e2c37498498f2469 100644 (file)
@@ -43,7 +43,7 @@ static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
 static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
 #endif
 
-static int __initdata no_watchdog;
+static int no_watchdog;
 
 
 /* boot commands */
index 76ae68303d3a3675265e61eccc213a0c4526d4e1..d522d8c1703e761eb27b4e2375eff9851b06690e 100644 (file)
@@ -16,11 +16,18 @@ int connect_req_to_link_param(struct cfcnfg *cnfg,
 {
        struct dev_info *dev_info;
        enum cfcnfg_phy_preference pref;
+       int res;
+
        memset(l, 0, sizeof(*l));
-       l->priority = s->priority;
+       /* In caif protocol low value is high priority */
+       l->priority = CAIF_PRIO_MAX - s->priority + 1;
 
-       if (s->link_name[0] != '\0')
-               l->phyid = cfcnfg_get_named(cnfg, s->link_name);
+       if (s->ifindex != 0){
+               res = cfcnfg_get_id_from_ifi(cnfg, s->ifindex);
+               if (res < 0)
+                       return res;
+               l->phyid = res;
+       }
        else {
                switch (s->link_selector) {
                case CAIF_LINK_HIGH_BANDW:
index b99369a055d13df6414421a28cfaee5d000c6c72..a42a408306e4a1c038aa6ad0d8fb3d0e2f923aa9 100644 (file)
@@ -307,6 +307,8 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what,
 
        case NETDEV_UNREGISTER:
                caifd = caif_get(dev);
+               if (caifd == NULL)
+                       break;
                netdev_info(dev, "unregister\n");
                atomic_set(&caifd->state, what);
                caif_device_destroy(dev);
index 2eca2dd0000fd7dce7fc614ed5e476f0ca886874..1bf0cf503796f27668d8dc8c1e9a733fd6e76bdd 100644 (file)
@@ -716,8 +716,7 @@ static int setsockopt(struct socket *sock,
 {
        struct sock *sk = sock->sk;
        struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
-       int prio, linksel;
-       struct ifreq ifreq;
+       int linksel;
 
        if (cf_sk->sk.sk_socket->state != SS_UNCONNECTED)
                return -ENOPROTOOPT;
@@ -735,33 +734,6 @@ static int setsockopt(struct socket *sock,
                release_sock(&cf_sk->sk);
                return 0;
 
-       case SO_PRIORITY:
-               if (lvl != SOL_SOCKET)
-                       goto bad_sol;
-               if (ol < sizeof(int))
-                       return -EINVAL;
-               if (copy_from_user(&prio, ov, sizeof(int)))
-                       return -EINVAL;
-               lock_sock(&(cf_sk->sk));
-               cf_sk->conn_req.priority = prio;
-               release_sock(&cf_sk->sk);
-               return 0;
-
-       case SO_BINDTODEVICE:
-               if (lvl != SOL_SOCKET)
-                       goto bad_sol;
-               if (ol < sizeof(struct ifreq))
-                       return -EINVAL;
-               if (copy_from_user(&ifreq, ov, sizeof(ifreq)))
-                       return -EFAULT;
-               lock_sock(&(cf_sk->sk));
-               strncpy(cf_sk->conn_req.link_name, ifreq.ifr_name,
-                       sizeof(cf_sk->conn_req.link_name));
-               cf_sk->conn_req.link_name
-                       [sizeof(cf_sk->conn_req.link_name)-1] = 0;
-               release_sock(&cf_sk->sk);
-               return 0;
-
        case CAIFSO_REQ_PARAM:
                if (lvl != SOL_CAIF)
                        goto bad_sol;
@@ -880,6 +852,18 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
        sock->state = SS_CONNECTING;
        sk->sk_state = CAIF_CONNECTING;
 
+       /* Check priority value comming from socket */
+       /* if priority value is out of range it will be ajusted */
+       if (cf_sk->sk.sk_priority > CAIF_PRIO_MAX)
+               cf_sk->conn_req.priority = CAIF_PRIO_MAX;
+       else if (cf_sk->sk.sk_priority < CAIF_PRIO_MIN)
+               cf_sk->conn_req.priority = CAIF_PRIO_MIN;
+       else
+               cf_sk->conn_req.priority = cf_sk->sk.sk_priority;
+
+       /*ifindex = id of the interface.*/
+       cf_sk->conn_req.ifindex = cf_sk->sk.sk_bound_dev_if;
+
        dbfs_atomic_inc(&cnt.num_connect_req);
        cf_sk->layer.receive = caif_sktrecv_cb;
        err = caif_connect_client(&cf_sk->conn_req,
@@ -905,6 +889,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
        cf_sk->maxframe = mtu - (headroom + tailroom);
        if (cf_sk->maxframe < 1) {
                pr_warn("CAIF Interface MTU too small (%d)\n", dev->mtu);
+               err = -ENODEV;
                goto out;
        }
 
@@ -1142,7 +1127,7 @@ static int caif_create(struct net *net, struct socket *sock, int protocol,
        set_rx_flow_on(cf_sk);
 
        /* Set default options on configuration */
-       cf_sk->conn_req.priority = CAIF_PRIO_NORMAL;
+       cf_sk->sk.sk_priority= CAIF_PRIO_NORMAL;
        cf_sk->conn_req.link_selector = CAIF_LINK_LOW_LATENCY;
        cf_sk->conn_req.protocol = protocol;
        /* Increase the number of sockets created. */
index 41adafd1891422ab1aa32a95a46aee7d9ae77b82..21ede141018abf698a58bcf946e0058d6d06c499 100644 (file)
@@ -173,18 +173,15 @@ static struct cfcnfg_phyinfo *cfcnfg_get_phyinfo(struct cfcnfg *cnfg,
        return NULL;
 }
 
-int cfcnfg_get_named(struct cfcnfg *cnfg, char *name)
+
+int cfcnfg_get_id_from_ifi(struct cfcnfg *cnfg, int ifi)
 {
        int i;
-
-       /* Try to match with specified name */
-       for (i = 0; i < MAX_PHY_LAYERS; i++) {
-               if (cnfg->phy_layers[i].frm_layer != NULL
-                   && strcmp(cnfg->phy_layers[i].phy_layer->name,
-                             name) == 0)
-                       return cnfg->phy_layers[i].frm_layer->id;
-       }
-       return 0;
+       for (i = 0; i < MAX_PHY_LAYERS; i++)
+               if (cnfg->phy_layers[i].frm_layer != NULL &&
+                               cnfg->phy_layers[i].ifindex == ifi)
+                       return i;
+       return -ENODEV;
 }
 
 int cfcnfg_disconn_adapt_layer(struct cfcnfg *cnfg, struct cflayer *adap_layer)
index 08f267a109aa3c677efc4a6795ccfea31fc8d581..3cd8f978e3098288d9d1e114347e1ba2c0e4936c 100644 (file)
@@ -361,11 +361,10 @@ void cfctrl_cancel_req(struct cflayer *layr, struct cflayer *adap_layer)
        struct cfctrl_request_info *p, *tmp;
        struct cfctrl *ctrl = container_obj(layr);
        spin_lock(&ctrl->info_list_lock);
-       pr_warn("enter\n");
 
        list_for_each_entry_safe(p, tmp, &ctrl->list, list) {
                if (p->client_layer == adap_layer) {
-                       pr_warn("cancel req :%d\n", p->sequence_no);
+                       pr_debug("cancel req :%d\n", p->sequence_no);
                        list_del(&p->list);
                        kfree(p);
                }
index 496fda9ac66f56bee42568e8c0386566c3208be4..11a2af4c162ab6a8324ebaf6b8063ced01b1aea6 100644 (file)
@@ -12,6 +12,8 @@
 #include <net/caif/cfsrvl.h>
 #include <net/caif/cfpkt.h>
 
+#define container_obj(layr) ((struct cfsrvl *) layr)
+
 static int cfdbgl_receive(struct cflayer *layr, struct cfpkt *pkt);
 static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt);
 
@@ -38,5 +40,17 @@ static int cfdbgl_receive(struct cflayer *layr, struct cfpkt *pkt)
 
 static int cfdbgl_transmit(struct cflayer *layr, struct cfpkt *pkt)
 {
+       struct cfsrvl *service = container_obj(layr);
+       struct caif_payload_info *info;
+       int ret;
+
+       if (!cfsrvl_ready(service, &ret))
+               return ret;
+
+       /* Add info for MUX-layer to route the packet out */
+       info = cfpkt_info(pkt);
+       info->channel_id = service->layer.id;
+       info->dev_info = &service->dev_info;
+
        return layr->dn->transmit(layr->dn, pkt);
 }
index bde8481e8d2574dd939f84595f8e4354370aa5a7..e2fb5fa757951a46e8d6be9326ffc1659f943232 100644 (file)
@@ -193,7 +193,7 @@ out:
 
 static int cfrfml_transmit_segment(struct cfrfml *rfml, struct cfpkt *pkt)
 {
-       caif_assert(cfpkt_getlen(pkt) >= rfml->fragment_size);
+       caif_assert(cfpkt_getlen(pkt) < rfml->fragment_size);
 
        /* Add info for MUX-layer to route the packet out. */
        cfpkt_info(pkt)->channel_id = rfml->serv.layer.id;
index 35dfb83184833302e616dca6b0985faeb533897d..0dd54a69dace255fcdf54732d982e8c521c574a5 100644 (file)
@@ -2131,7 +2131,7 @@ static struct netdev_queue *dev_pick_tx(struct net_device *dev,
        } else {
                struct sock *sk = skb->sk;
                queue_index = sk_tx_queue_get(sk);
-               if (queue_index < 0) {
+               if (queue_index < 0 || queue_index >= dev->real_num_tx_queues) {
 
                        queue_index = 0;
                        if (dev->real_num_tx_queues > 1)
index a29edf2219c8437b811bcce27fdd2cd9fca0a9fc..c079cc0ec6515fe212aecd27303c2b5671a5d60d 100644 (file)
@@ -47,11 +47,8 @@ extern int fib_detect_death(struct fib_info *fi, int order,
 static inline void fib_result_assign(struct fib_result *res,
                                     struct fib_info *fi)
 {
-       if (res->fi != NULL)
-               fib_info_put(res->fi);
+       /* we used to play games with refcounts, but we now use RCU */
        res->fi = fi;
-       if (fi != NULL)
-               atomic_inc(&fi->fib_clntref);
 }
 
 #endif /* _FIB_LOOKUP_H */
index ba80426658498ba4082c54a19c5af2d2c00cdb10..2ada17129fce6ac9a7285f6033e30d0a9bc4b98a 100644 (file)
@@ -490,9 +490,11 @@ static int inet_csk_diag_dump(struct sock *sk,
 {
        struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
 
-       if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
+       if (nlmsg_attrlen(cb->nlh, sizeof(*r))) {
                struct inet_diag_entry entry;
-               struct rtattr *bc = (struct rtattr *)(r + 1);
+               const struct nlattr *bc = nlmsg_find_attr(cb->nlh,
+                                                         sizeof(*r),
+                                                         INET_DIAG_REQ_BYTECODE);
                struct inet_sock *inet = inet_sk(sk);
 
                entry.family = sk->sk_family;
@@ -512,7 +514,7 @@ static int inet_csk_diag_dump(struct sock *sk,
                entry.dport = ntohs(inet->inet_dport);
                entry.userlocks = sk->sk_userlocks;
 
-               if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
+               if (!inet_diag_bc_run(nla_data(bc), nla_len(bc), &entry))
                        return 0;
        }
 
@@ -527,9 +529,11 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
 {
        struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
 
-       if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
+       if (nlmsg_attrlen(cb->nlh, sizeof(*r))) {
                struct inet_diag_entry entry;
-               struct rtattr *bc = (struct rtattr *)(r + 1);
+               const struct nlattr *bc = nlmsg_find_attr(cb->nlh,
+                                                         sizeof(*r),
+                                                         INET_DIAG_REQ_BYTECODE);
 
                entry.family = tw->tw_family;
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
@@ -548,7 +552,7 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
                entry.dport = ntohs(tw->tw_dport);
                entry.userlocks = 0;
 
-               if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
+               if (!inet_diag_bc_run(nla_data(bc), nla_len(bc), &entry))
                        return 0;
        }
 
@@ -618,7 +622,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
        struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct listen_sock *lopt;
-       struct rtattr *bc = NULL;
+       const struct nlattr *bc = NULL;
        struct inet_sock *inet = inet_sk(sk);
        int j, s_j;
        int reqnum, s_reqnum;
@@ -638,8 +642,9 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
        if (!lopt || !lopt->qlen)
                goto out;
 
-       if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
-               bc = (struct rtattr *)(r + 1);
+       if (nlmsg_attrlen(cb->nlh, sizeof(*r))) {
+               bc = nlmsg_find_attr(cb->nlh, sizeof(*r),
+                                    INET_DIAG_REQ_BYTECODE);
                entry.sport = inet->inet_num;
                entry.userlocks = sk->sk_userlocks;
        }
@@ -672,8 +677,8 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
                                        &ireq->rmt_addr;
                                entry.dport = ntohs(ireq->rmt_port);
 
-                               if (!inet_diag_bc_run(RTA_DATA(bc),
-                                                   RTA_PAYLOAD(bc), &entry))
+                               if (!inet_diag_bc_run(nla_data(bc),
+                                                     nla_len(bc), &entry))
                                        continue;
                        }
 
index 3cad2591ace0c15fdad446ab528b0f40c2624d09..3fac340a28d5394bd95bd649d5bcee3dcb3d24df 100644 (file)
@@ -927,6 +927,7 @@ static int get_info(struct net *net, void __user *user,
                        private = &tmp;
                }
 #endif
+               memset(&info, 0, sizeof(info));
                info.valid_hooks = t->valid_hooks;
                memcpy(info.hook_entry, private->hook_entry,
                       sizeof(info.hook_entry));
index d31b007a6d80dcda45f7f7913ec72af7556b79bf..a846d633b3b6f04a3ed72be1d884e484d3efa030 100644 (file)
@@ -1124,6 +1124,7 @@ static int get_info(struct net *net, void __user *user,
                        private = &tmp;
                }
 #endif
+               memset(&info, 0, sizeof(info));
                info.valid_hooks = t->valid_hooks;
                memcpy(info.hook_entry, private->hook_entry,
                       sizeof(info.hook_entry));
index 295c97431e4358408dc45fc7c493536bb41434fc..c04787ce1a71203e1346830450b0a130e358defc 100644 (file)
@@ -47,26 +47,6 @@ __nf_nat_proto_find(u_int8_t protonum)
        return rcu_dereference(nf_nat_protos[protonum]);
 }
 
-static const struct nf_nat_protocol *
-nf_nat_proto_find_get(u_int8_t protonum)
-{
-       const struct nf_nat_protocol *p;
-
-       rcu_read_lock();
-       p = __nf_nat_proto_find(protonum);
-       if (!try_module_get(p->me))
-               p = &nf_nat_unknown_protocol;
-       rcu_read_unlock();
-
-       return p;
-}
-
-static void
-nf_nat_proto_put(const struct nf_nat_protocol *p)
-{
-       module_put(p->me);
-}
-
 /* We keep an extra hash for each conntrack, for fast searching. */
 static inline unsigned int
 hash_by_src(const struct net *net, u16 zone,
@@ -588,6 +568,26 @@ static struct nf_ct_ext_type nat_extend __read_mostly = {
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_conntrack.h>
 
+static const struct nf_nat_protocol *
+nf_nat_proto_find_get(u_int8_t protonum)
+{
+       const struct nf_nat_protocol *p;
+
+       rcu_read_lock();
+       p = __nf_nat_proto_find(protonum);
+       if (!try_module_get(p->me))
+               p = &nf_nat_unknown_protocol;
+       rcu_read_unlock();
+
+       return p;
+}
+
+static void
+nf_nat_proto_put(const struct nf_nat_protocol *p)
+{
+       module_put(p->me);
+}
+
 static const struct nla_policy protonat_nla_policy[CTA_PROTONAT_MAX+1] = {
        [CTA_PROTONAT_PORT_MIN] = { .type = NLA_U16 },
        [CTA_PROTONAT_PORT_MAX] = { .type = NLA_U16 },
index 51df035897e77dfa5b89e6328817cfcb638702cb..455582384eced0b9242a40ea523ac31c8d6e08f4 100644 (file)
@@ -1137,6 +1137,7 @@ static int get_info(struct net *net, void __user *user,
                        private = &tmp;
                }
 #endif
+               memset(&info, 0, sizeof(info));
                info.valid_hooks = t->valid_hooks;
                memcpy(info.hook_entry, private->hook_entry,
                       sizeof(info.hook_entry));
index 25661f968f3fb2c2976575f4233fd03c42edb863..fc328339be99f5c0c1fe5ffcb484e72b51b63e90 100644 (file)
@@ -2741,6 +2741,7 @@ static void __net_exit ip6_route_net_exit(struct net *net)
        kfree(net->ipv6.ip6_prohibit_entry);
        kfree(net->ipv6.ip6_blk_hole_entry);
 #endif
+       dst_entries_destroy(&net->ipv6.ip6_dst_ops);
 }
 
 static struct pernet_operations ip6_route_net_ops = {
@@ -2832,5 +2833,6 @@ void ip6_route_cleanup(void)
        xfrm6_fini();
        fib6_gc_cleanup();
        unregister_pernet_subsys(&ip6_route_net_ops);
+       dst_entries_destroy(&ip6_dst_blackhole_ops);
        kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
 }
index 104ec3b283d4159f610ef61548beb512d053dcd3..b8dbae82fab8612974d603c42b4cbac3b0509165 100644 (file)
@@ -249,7 +249,7 @@ static int l2tp_dfs_seq_open(struct inode *inode, struct file *file)
        struct seq_file *seq;
        int rc = -ENOMEM;
 
-       pd = kzalloc(GFP_KERNEL, sizeof(*pd));
+       pd = kzalloc(sizeof(*pd), GFP_KERNEL);
        if (pd == NULL)
                goto out;
 
index 1eacf8d9966aa292f7f051964f822a00c0ab6605..27a5ea6b6a0ff1a644205ca705f717c78b4dcc84 100644 (file)
@@ -1312,7 +1312,8 @@ void *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced, int nulls)
        if (!hash) {
                *vmalloced = 1;
                printk(KERN_WARNING "nf_conntrack: falling back to vmalloc.\n");
-               hash = __vmalloc(sz, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+               hash = __vmalloc(sz, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
+                                PAGE_KERNEL);
        }
 
        if (hash && nulls)
index ed6d929580236c1b4aa77a42db959c9e522f2fc5..dc7bb74110df22818b42222450f0141068b79b6d 100644 (file)
@@ -292,6 +292,12 @@ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto)
 
                for (i = 0; i < MAX_NF_CT_PROTO; i++)
                        proto_array[i] = &nf_conntrack_l4proto_generic;
+
+               /* Before making proto_array visible to lockless readers,
+                * we must make sure its content is committed to memory.
+                */
+               smp_wmb();
+
                nf_ct_protos[l4proto->l3proto] = proto_array;
        } else if (nf_ct_protos[l4proto->l3proto][l4proto->l4proto] !=
                                        &nf_conntrack_l4proto_generic) {
index c390156b426fc936c6b05fd607f4c32ddb1e3a81..aeec1d483b17e6f65c858e1510c7752965e35260 100644 (file)
@@ -134,8 +134,12 @@ static int rds_loop_conn_alloc(struct rds_connection *conn, gfp_t gfp)
 static void rds_loop_conn_free(void *arg)
 {
        struct rds_loop_connection *lc = arg;
+       unsigned long flags;
+
        rdsdebug("lc %p\n", lc);
+       spin_lock_irqsave(&loop_conns_lock, flags);
        list_del(&lc->loop_node);
+       spin_unlock_irqrestore(&loop_conns_lock, flags);
        kfree(lc);
 }
 
index 08a8c6cf2d100f8f05a6c932d8190326277747e9..8e0a32001c90c531a2ad8361dc4bb0c399b812fe 100644 (file)
@@ -221,7 +221,13 @@ static int rds_tcp_conn_alloc(struct rds_connection *conn, gfp_t gfp)
 static void rds_tcp_conn_free(void *arg)
 {
        struct rds_tcp_connection *tc = arg;
+       unsigned long flags;
        rdsdebug("freeing tc %p\n", tc);
+
+       spin_lock_irqsave(&rds_tcp_conn_lock, flags);
+       list_del(&tc->t_tcp_node);
+       spin_unlock_irqrestore(&rds_tcp_conn_lock, flags);
+
        kmem_cache_free(rds_tcp_conn_slab, tc);
 }
 
index 37dff78e9cb17c6fcf35e5302d57b84dd5e9f5f9..d49c40fb7e0960daa905353e714e9317dd38088b 100644 (file)
@@ -34,8 +34,6 @@ struct cgroup_subsys net_cls_subsys = {
        .populate       = cgrp_populate,
 #ifdef CONFIG_NET_CLS_CGROUP
        .subsys_id      = net_cls_subsys_id,
-#else
-#define net_cls_subsys_id net_cls_subsys.subsys_id
 #endif
        .module         = THIS_MODULE,
 };
index 763253257411af1db91b3e25a78af8e687523342..ea8f566e720c7bd9ed508647c080c5c554edba2b 100644 (file)
@@ -103,7 +103,8 @@ retry:
 
 static void em_text_destroy(struct tcf_proto *tp, struct tcf_ematch *m)
 {
-       textsearch_destroy(EM_TEXT_PRIV(m)->config);
+       if (EM_TEXT_PRIV(m) && EM_TEXT_PRIV(m)->config)
+               textsearch_destroy(EM_TEXT_PRIV(m)->config);
 }
 
 static int em_text_dump(struct sk_buff *skb, struct tcf_ematch *m)
index 771bab00754b0baff1a5c7a95892028857c8b84d..3a8c4c419cd4051ce0ce7a586b3d93417f768cb2 100644 (file)
@@ -134,15 +134,15 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
                case X25_FAC_CLASS_D:
                        switch (*p) {
                        case X25_FAC_CALLING_AE:
-                               if (p[1] > X25_MAX_DTE_FACIL_LEN)
-                                       break;
+                               if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1)
+                                       return 0;
                                dte_facs->calling_len = p[2];
                                memcpy(dte_facs->calling_ae, &p[3], p[1] - 1);
                                *vc_fac_mask |= X25_MASK_CALLING_AE;
                                break;
                        case X25_FAC_CALLED_AE:
-                               if (p[1] > X25_MAX_DTE_FACIL_LEN)
-                                       break;
+                               if (p[1] > X25_MAX_DTE_FACIL_LEN || p[1] <= 1)
+                                       return 0;
                                dte_facs->called_len = p[2];
                                memcpy(dte_facs->called_ae, &p[3], p[1] - 1);
                                *vc_fac_mask |= X25_MASK_CALLED_AE;
index 63178961efac00488d36e7c8fc3d21f00e036e2e..f729f022be69bc8c32b1008e8943c92cf36c1e28 100644 (file)
@@ -119,6 +119,8 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
                                                &x25->vc_facil_mask);
                        if (len > 0)
                                skb_pull(skb, len);
+                       else
+                               return -1;
                        /*
                         *      Copy any Call User Data.
                         */